diff options
author | Ben Straub <bs@github.com> | 2013-11-14 14:05:52 -0800 |
---|---|---|
committer | Ben Straub <bs@github.com> | 2013-11-14 14:05:52 -0800 |
commit | 1782038144ef3413831801bb9c2f3038a84ac6f4 (patch) | |
tree | f074cc30890a20f5418c10fae1815ca516588a27 /tests/index | |
parent | 7b947bf5cc59eefa83c28eb5f5fd8434207ebb8b (diff) | |
download | libgit2-1782038144ef3413831801bb9c2f3038a84ac6f4.tar.gz |
Rename tests-clar to tests
Diffstat (limited to 'tests/index')
-rw-r--r-- | tests/index/addall.c | 258 | ||||
-rw-r--r-- | tests/index/conflicts.c | 287 | ||||
-rw-r--r-- | tests/index/filemodes.c | 154 | ||||
-rw-r--r-- | tests/index/inmemory.c | 22 | ||||
-rw-r--r-- | tests/index/names.c | 148 | ||||
-rw-r--r-- | tests/index/read_tree.c | 46 | ||||
-rw-r--r-- | tests/index/rename.c | 50 | ||||
-rw-r--r-- | tests/index/reuc.c | 372 | ||||
-rw-r--r-- | tests/index/stage.c | 62 | ||||
-rw-r--r-- | tests/index/tests.c | 537 |
10 files changed, 1936 insertions, 0 deletions
diff --git a/tests/index/addall.c b/tests/index/addall.c new file mode 100644 index 000000000..44c51279d --- /dev/null +++ b/tests/index/addall.c @@ -0,0 +1,258 @@ +#include "clar_libgit2.h" +#include "../status/status_helpers.h" +#include "posix.h" +#include "fileops.h" + +git_repository *g_repo = NULL; + +void test_index_addall__initialize(void) +{ +} + +void test_index_addall__cleanup(void) +{ + git_repository_free(g_repo); + g_repo = NULL; +} + +#define STATUS_INDEX_FLAGS \ + (GIT_STATUS_INDEX_NEW | GIT_STATUS_INDEX_MODIFIED | \ + GIT_STATUS_INDEX_DELETED | GIT_STATUS_INDEX_RENAMED | \ + GIT_STATUS_INDEX_TYPECHANGE) + +#define STATUS_WT_FLAGS \ + (GIT_STATUS_WT_NEW | GIT_STATUS_WT_MODIFIED | \ + GIT_STATUS_WT_DELETED | GIT_STATUS_WT_TYPECHANGE | \ + GIT_STATUS_WT_RENAMED) + +typedef struct { + size_t index_adds; + size_t index_dels; + size_t index_mods; + size_t wt_adds; + size_t wt_dels; + size_t wt_mods; + size_t ignores; +} index_status_counts; + +static int index_status_cb( + const char *path, unsigned int status_flags, void *payload) +{ + index_status_counts *vals = payload; + + /* cb_status__print(path, status_flags, NULL); */ + + GIT_UNUSED(path); + + if (status_flags & GIT_STATUS_INDEX_NEW) + vals->index_adds++; + if (status_flags & GIT_STATUS_INDEX_MODIFIED) + vals->index_mods++; + if (status_flags & GIT_STATUS_INDEX_DELETED) + vals->index_dels++; + if (status_flags & GIT_STATUS_INDEX_TYPECHANGE) + vals->index_mods++; + + if (status_flags & GIT_STATUS_WT_NEW) + vals->wt_adds++; + if (status_flags & GIT_STATUS_WT_MODIFIED) + vals->wt_mods++; + if (status_flags & GIT_STATUS_WT_DELETED) + vals->wt_dels++; + if (status_flags & GIT_STATUS_WT_TYPECHANGE) + vals->wt_mods++; + + if (status_flags & GIT_STATUS_IGNORED) + vals->ignores++; + + return 0; +} + +static void check_status_at_line( + git_repository *repo, + size_t index_adds, size_t index_dels, size_t index_mods, + size_t wt_adds, size_t wt_dels, size_t wt_mods, size_t ignores, + const char *file, int line) +{ + index_status_counts vals; + + memset(&vals, 0, sizeof(vals)); + + cl_git_pass(git_status_foreach(repo, index_status_cb, &vals)); + + clar__assert_equal( + file,line,"wrong index adds", 1, "%"PRIuZ, index_adds, vals.index_adds); + clar__assert_equal( + file,line,"wrong index dels", 1, "%"PRIuZ, index_dels, vals.index_dels); + clar__assert_equal( + file,line,"wrong index mods", 1, "%"PRIuZ, index_mods, vals.index_mods); + clar__assert_equal( + file,line,"wrong workdir adds", 1, "%"PRIuZ, wt_adds, vals.wt_adds); + clar__assert_equal( + file,line,"wrong workdir dels", 1, "%"PRIuZ, wt_dels, vals.wt_dels); + clar__assert_equal( + file,line,"wrong workdir mods", 1, "%"PRIuZ, wt_mods, vals.wt_mods); + clar__assert_equal( + file,line,"wrong ignores", 1, "%"PRIuZ, ignores, vals.ignores); +} + +#define check_status(R,IA,ID,IM,WA,WD,WM,IG) \ + check_status_at_line(R,IA,ID,IM,WA,WD,WM,IG,__FILE__,__LINE__) + +static void check_stat_data(git_index *index, const char *path, bool match) +{ + const git_index_entry *entry; + struct stat st; + + cl_must_pass(p_lstat(path, &st)); + + /* skip repo base dir name */ + while (*path != '/') + ++path; + ++path; + + entry = git_index_get_bypath(index, path, 0); + cl_assert(entry); + + if (match) { + cl_assert(st.st_ctime == entry->ctime.seconds); + cl_assert(st.st_mtime == entry->mtime.seconds); + cl_assert(st.st_size == entry->file_size); + cl_assert(st.st_uid == entry->uid); + cl_assert(st.st_gid == entry->gid); + cl_assert_equal_i_fmt( + GIT_MODE_TYPE(st.st_mode), GIT_MODE_TYPE(entry->mode), "%07o"); + if (cl_is_chmod_supported()) + cl_assert_equal_b( + GIT_PERMS_IS_EXEC(st.st_mode), GIT_PERMS_IS_EXEC(entry->mode)); + } else { + /* most things will still match */ + cl_assert(st.st_size != entry->file_size); + /* would check mtime, but with second resolution it won't work :( */ + } +} + +void test_index_addall__repo_lifecycle(void) +{ + int error; + git_index *index; + git_strarray paths = { NULL, 0 }; + char *strs[1]; + + cl_git_pass(git_repository_init(&g_repo, "addall", false)); + check_status(g_repo, 0, 0, 0, 0, 0, 0, 0); + + cl_git_pass(git_repository_index(&index, g_repo)); + + cl_git_mkfile("addall/file.foo", "a file"); + check_status(g_repo, 0, 0, 0, 1, 0, 0, 0); + + cl_git_mkfile("addall/.gitignore", "*.foo\n"); + check_status(g_repo, 0, 0, 0, 1, 0, 0, 1); + + cl_git_mkfile("addall/file.bar", "another file"); + check_status(g_repo, 0, 0, 0, 2, 0, 0, 1); + + strs[0] = "file.*"; + paths.strings = strs; + paths.count = 1; + + cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); + check_stat_data(index, "addall/file.bar", true); + check_status(g_repo, 1, 0, 0, 1, 0, 0, 1); + + cl_git_rewritefile("addall/file.bar", "new content for file"); + check_stat_data(index, "addall/file.bar", false); + check_status(g_repo, 1, 0, 0, 1, 0, 1, 1); + + cl_git_mkfile("addall/file.zzz", "yet another one"); + cl_git_mkfile("addall/other.zzz", "yet another one"); + cl_git_mkfile("addall/more.zzz", "yet another one"); + check_status(g_repo, 1, 0, 0, 4, 0, 1, 1); + + cl_git_pass(git_index_update_all(index, NULL, NULL, NULL)); + check_stat_data(index, "addall/file.bar", true); + check_status(g_repo, 1, 0, 0, 4, 0, 0, 1); + + cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); + check_stat_data(index, "addall/file.zzz", true); + check_status(g_repo, 2, 0, 0, 3, 0, 0, 1); + + cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "first commit"); + check_status(g_repo, 0, 0, 0, 3, 0, 0, 1); + + /* attempt to add an ignored file - does nothing */ + strs[0] = "file.foo"; + cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); + check_status(g_repo, 0, 0, 0, 3, 0, 0, 1); + + /* add with check - should generate error */ + error = git_index_add_all( + index, &paths, GIT_INDEX_ADD_CHECK_PATHSPEC, NULL, NULL); + cl_assert_equal_i(GIT_EINVALIDSPEC, error); + check_status(g_repo, 0, 0, 0, 3, 0, 0, 1); + + /* add with force - should allow */ + cl_git_pass(git_index_add_all( + index, &paths, GIT_INDEX_ADD_FORCE, NULL, NULL)); + check_stat_data(index, "addall/file.foo", true); + check_status(g_repo, 1, 0, 0, 3, 0, 0, 0); + + /* now it's in the index, so regular add should work */ + cl_git_rewritefile("addall/file.foo", "new content for file"); + check_stat_data(index, "addall/file.foo", false); + check_status(g_repo, 1, 0, 0, 3, 0, 1, 0); + + cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); + check_stat_data(index, "addall/file.foo", true); + check_status(g_repo, 1, 0, 0, 3, 0, 0, 0); + + cl_git_pass(git_index_add_bypath(index, "more.zzz")); + check_stat_data(index, "addall/more.zzz", true); + check_status(g_repo, 2, 0, 0, 2, 0, 0, 0); + + cl_git_rewritefile("addall/file.zzz", "new content for file"); + check_status(g_repo, 2, 0, 0, 2, 0, 1, 0); + + cl_git_pass(git_index_add_bypath(index, "file.zzz")); + check_stat_data(index, "addall/file.zzz", true); + check_status(g_repo, 2, 0, 1, 2, 0, 0, 0); + + strs[0] = "*.zzz"; + cl_git_pass(git_index_remove_all(index, &paths, NULL, NULL)); + check_status(g_repo, 1, 1, 0, 4, 0, 0, 0); + + cl_git_pass(git_index_add_bypath(index, "file.zzz")); + check_status(g_repo, 1, 0, 1, 3, 0, 0, 0); + + cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "second commit"); + check_status(g_repo, 0, 0, 0, 3, 0, 0, 0); + + cl_must_pass(p_unlink("addall/file.zzz")); + check_status(g_repo, 0, 0, 0, 3, 1, 0, 0); + + /* update_all should be able to remove entries */ + cl_git_pass(git_index_update_all(index, NULL, NULL, NULL)); + check_status(g_repo, 0, 1, 0, 3, 0, 0, 0); + + strs[0] = "*"; + cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); + check_status(g_repo, 3, 1, 0, 0, 0, 0, 0); + + /* must be able to remove at any position while still updating other files */ + cl_must_pass(p_unlink("addall/.gitignore")); + cl_git_rewritefile("addall/file.zzz", "reconstructed file"); + cl_git_rewritefile("addall/more.zzz", "altered file reality"); + check_status(g_repo, 3, 1, 0, 1, 1, 1, 0); + + cl_git_pass(git_index_update_all(index, NULL, NULL, NULL)); + check_status(g_repo, 2, 1, 0, 1, 0, 0, 0); + /* this behavior actually matches 'git add -u' where "file.zzz" has + * been removed from the index, so when you go to update, even though + * it exists in the HEAD, it is not re-added to the index, leaving it + * as a DELETE when comparing HEAD to index and as an ADD comparing + * index to worktree + */ + + git_index_free(index); +} diff --git a/tests/index/conflicts.c b/tests/index/conflicts.c new file mode 100644 index 000000000..6311b3a75 --- /dev/null +++ b/tests/index/conflicts.c @@ -0,0 +1,287 @@ +#include "clar_libgit2.h" +#include "index.h" +#include "git2/repository.h" + +static git_repository *repo; +static git_index *repo_index; + +#define TEST_REPO_PATH "mergedrepo" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + +#define CONFLICTS_ONE_ANCESTOR_OID "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81" +#define CONFLICTS_ONE_OUR_OID "6aea5f295304c36144ad6e9247a291b7f8112399" +#define CONFLICTS_ONE_THEIR_OID "516bd85f78061e09ccc714561d7b504672cb52da" + +#define CONFLICTS_TWO_ANCESTOR_OID "84af62840be1b1c47b778a8a249f3ff45155038c" +#define CONFLICTS_TWO_OUR_OID "8b3f43d2402825c200f835ca1762413e386fd0b2" +#define CONFLICTS_TWO_THEIR_OID "220bd62631c8cf7a83ef39c6b94595f00517211e" + +#define TEST_ANCESTOR_OID "f00ff00ff00ff00ff00ff00ff00ff00ff00ff00f" +#define TEST_OUR_OID "b44bb44bb44bb44bb44bb44bb44bb44bb44bb44b" +#define TEST_THEIR_OID "0123456789abcdef0123456789abcdef01234567" + +// Fixture setup and teardown +void test_index_conflicts__initialize(void) +{ + repo = cl_git_sandbox_init("mergedrepo"); + git_repository_index(&repo_index, repo); +} + +void test_index_conflicts__cleanup(void) +{ + git_index_free(repo_index); + repo_index = NULL; + + cl_git_sandbox_cleanup(); +} + +void test_index_conflicts__add(void) +{ + git_index_entry ancestor_entry, our_entry, their_entry; + + cl_assert(git_index_entrycount(repo_index) == 8); + + memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); + memset(&our_entry, 0x0, sizeof(git_index_entry)); + memset(&their_entry, 0x0, sizeof(git_index_entry)); + + ancestor_entry.path = "test-one.txt"; + ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT); + git_oid_fromstr(&ancestor_entry.oid, TEST_ANCESTOR_OID); + + our_entry.path = "test-one.txt"; + ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT); + git_oid_fromstr(&our_entry.oid, TEST_OUR_OID); + + their_entry.path = "test-one.txt"; + ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT); + git_oid_fromstr(&their_entry.oid, TEST_THEIR_OID); + + cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry)); + + cl_assert(git_index_entrycount(repo_index) == 11); +} + +void test_index_conflicts__add_fixes_incorrect_stage(void) +{ + git_index_entry ancestor_entry, our_entry, their_entry; + const git_index_entry *conflict_entry[3]; + + cl_assert(git_index_entrycount(repo_index) == 8); + + memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); + memset(&our_entry, 0x0, sizeof(git_index_entry)); + memset(&their_entry, 0x0, sizeof(git_index_entry)); + + ancestor_entry.path = "test-one.txt"; + ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT); + git_oid_fromstr(&ancestor_entry.oid, TEST_ANCESTOR_OID); + + our_entry.path = "test-one.txt"; + ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT); + git_oid_fromstr(&our_entry.oid, TEST_OUR_OID); + + their_entry.path = "test-one.txt"; + ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT); + git_oid_fromstr(&their_entry.oid, TEST_THEIR_OID); + + cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry)); + + cl_assert(git_index_entrycount(repo_index) == 11); + + cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], repo_index, "test-one.txt")); + + cl_assert(git_index_entry_stage(conflict_entry[0]) == 1); + cl_assert(git_index_entry_stage(conflict_entry[1]) == 2); + cl_assert(git_index_entry_stage(conflict_entry[2]) == 3); +} + +void test_index_conflicts__get(void) +{ + const git_index_entry *conflict_entry[3]; + git_oid oid; + + cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], + &conflict_entry[2], repo_index, "conflicts-one.txt")); + + cl_assert_equal_s("conflicts-one.txt", conflict_entry[0]->path); + + git_oid_fromstr(&oid, CONFLICTS_ONE_ANCESTOR_OID); + cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0); + + git_oid_fromstr(&oid, CONFLICTS_ONE_OUR_OID); + cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0); + + git_oid_fromstr(&oid, CONFLICTS_ONE_THEIR_OID); + cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0); + + cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], + &conflict_entry[2], repo_index, "conflicts-two.txt")); + + cl_assert_equal_s("conflicts-two.txt", conflict_entry[0]->path); + + git_oid_fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID); + cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0); + + git_oid_fromstr(&oid, CONFLICTS_TWO_OUR_OID); + cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0); + + git_oid_fromstr(&oid, CONFLICTS_TWO_THEIR_OID); + cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0); +} + +void test_index_conflicts__iterate(void) +{ + git_index_conflict_iterator *iterator; + const git_index_entry *conflict_entry[3]; + git_oid oid; + + cl_git_pass(git_index_conflict_iterator_new(&iterator, repo_index)); + + cl_git_pass(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator)); + + git_oid_fromstr(&oid, CONFLICTS_ONE_ANCESTOR_OID); + cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0); + cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0); + + git_oid_fromstr(&oid, CONFLICTS_ONE_OUR_OID); + cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0); + cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0); + + git_oid_fromstr(&oid, CONFLICTS_ONE_THEIR_OID); + cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0); + cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0); + + cl_git_pass(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator)); + + git_oid_fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID); + cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0); + cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0); + + git_oid_fromstr(&oid, CONFLICTS_TWO_OUR_OID); + cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0); + cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0); + + git_oid_fromstr(&oid, CONFLICTS_TWO_THEIR_OID); + cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0); + cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0); + + cl_assert(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator) == GIT_ITEROVER); + + cl_assert(conflict_entry[0] == NULL); + cl_assert(conflict_entry[2] == NULL); + cl_assert(conflict_entry[2] == NULL); + + git_index_conflict_iterator_free(iterator); +} + +void test_index_conflicts__remove(void) +{ + const git_index_entry *entry; + size_t i; + + cl_assert(git_index_entrycount(repo_index) == 8); + + cl_git_pass(git_index_conflict_remove(repo_index, "conflicts-one.txt")); + cl_assert(git_index_entrycount(repo_index) == 5); + + for (i = 0; i < git_index_entrycount(repo_index); i++) { + cl_assert(entry = git_index_get_byindex(repo_index, i)); + cl_assert(strcmp(entry->path, "conflicts-one.txt") != 0); + } + + cl_git_pass(git_index_conflict_remove(repo_index, "conflicts-two.txt")); + cl_assert(git_index_entrycount(repo_index) == 2); + + for (i = 0; i < git_index_entrycount(repo_index); i++) { + cl_assert(entry = git_index_get_byindex(repo_index, i)); + cl_assert(strcmp(entry->path, "conflicts-two.txt") != 0); + } +} + +void test_index_conflicts__moved_to_reuc_on_add(void) +{ + const git_index_entry *entry; + size_t i; + + cl_assert(git_index_entrycount(repo_index) == 8); + + cl_git_mkfile("./mergedrepo/conflicts-one.txt", "new-file\n"); + + cl_git_pass(git_index_add_bypath(repo_index, "conflicts-one.txt")); + + cl_assert(git_index_entrycount(repo_index) == 6); + + for (i = 0; i < git_index_entrycount(repo_index); i++) { + cl_assert(entry = git_index_get_byindex(repo_index, i)); + + if (strcmp(entry->path, "conflicts-one.txt") == 0) + cl_assert(git_index_entry_stage(entry) == 0); + } +} + +void test_index_conflicts__moved_to_reuc_on_remove(void) +{ + const git_index_entry *entry; + size_t i; + + cl_assert(git_index_entrycount(repo_index) == 8); + + cl_git_pass(p_unlink("./mergedrepo/conflicts-one.txt")); + + cl_git_pass(git_index_remove_bypath(repo_index, "conflicts-one.txt")); + + cl_assert(git_index_entrycount(repo_index) == 5); + + for (i = 0; i < git_index_entrycount(repo_index); i++) { + cl_assert(entry = git_index_get_byindex(repo_index, i)); + cl_assert(strcmp(entry->path, "conflicts-one.txt") != 0); + } +} + +void test_index_conflicts__remove_all_conflicts(void) +{ + size_t i; + const git_index_entry *entry; + + cl_assert(git_index_entrycount(repo_index) == 8); + + cl_assert_equal_i(true, git_index_has_conflicts(repo_index)); + + git_index_conflict_cleanup(repo_index); + + cl_assert_equal_i(false, git_index_has_conflicts(repo_index)); + + cl_assert(git_index_entrycount(repo_index) == 2); + + for (i = 0; i < git_index_entrycount(repo_index); i++) { + cl_assert(entry = git_index_get_byindex(repo_index, i)); + cl_assert(git_index_entry_stage(entry) == 0); + } +} + +void test_index_conflicts__partial(void) +{ + git_index_entry ancestor_entry, our_entry, their_entry; + const git_index_entry *conflict_entry[3]; + + cl_assert(git_index_entrycount(repo_index) == 8); + + memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); + memset(&our_entry, 0x0, sizeof(git_index_entry)); + memset(&their_entry, 0x0, sizeof(git_index_entry)); + + ancestor_entry.path = "test-one.txt"; + ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT); + git_oid_fromstr(&ancestor_entry.oid, TEST_ANCESTOR_OID); + + cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, NULL, NULL)); + cl_assert(git_index_entrycount(repo_index) == 9); + + cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], + &conflict_entry[2], repo_index, "test-one.txt")); + + cl_assert(git_oid_cmp(&ancestor_entry.oid, &conflict_entry[0]->oid) == 0); + cl_assert(conflict_entry[1] == NULL); + cl_assert(conflict_entry[2] == NULL); +} diff --git a/tests/index/filemodes.c b/tests/index/filemodes.c new file mode 100644 index 000000000..013932696 --- /dev/null +++ b/tests/index/filemodes.c @@ -0,0 +1,154 @@ +#include "clar_libgit2.h" +#include "buffer.h" +#include "posix.h" +#include "index.h" + +static git_repository *g_repo = NULL; + +void test_index_filemodes__initialize(void) +{ + g_repo = cl_git_sandbox_init("filemodes"); +} + +void test_index_filemodes__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_index_filemodes__read(void) +{ + git_index *index; + unsigned int i; + static bool expected[6] = { 0, 1, 0, 1, 0, 1 }; + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_assert_equal_i(6, (int)git_index_entrycount(index)); + + for (i = 0; i < 6; ++i) { + const git_index_entry *entry = git_index_get_byindex(index, i); + cl_assert(entry != NULL); + cl_assert(((entry->mode & 0100) ? 1 : 0) == expected[i]); + } + + git_index_free(index); +} + +static void replace_file_with_mode( + const char *filename, const char *backup, unsigned int create_mode) +{ + git_buf path = GIT_BUF_INIT, content = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&path, "filemodes", filename)); + cl_git_pass(git_buf_printf(&content, "%s as %08u (%d)", + filename, create_mode, rand())); + + cl_git_pass(p_rename(path.ptr, backup)); + cl_git_write2file( + path.ptr, content.ptr, content.size, + O_WRONLY|O_CREAT|O_TRUNC, create_mode); + + git_buf_free(&path); + git_buf_free(&content); +} + +#define add_and_check_mode(I,F,X) add_and_check_mode_(I,F,X,__FILE__,__LINE__) + +static void add_and_check_mode_( + git_index *index, const char *filename, unsigned int expect_mode, + const char *file, int line) +{ + size_t pos; + const git_index_entry *entry; + + cl_git_pass(git_index_add_bypath(index, filename)); + + clar__assert(!git_index_find(&pos, index, filename), + file, line, "Cannot find index entry", NULL, 1); + + entry = git_index_get_byindex(index, pos); + + clar__assert_equal(file, line, "Expected mode does not match index", + 1, "%07o", (unsigned int)entry->mode, (unsigned int)expect_mode); +} + +void test_index_filemodes__untrusted(void) +{ + git_index *index; + + cl_repo_set_bool(g_repo, "core.filemode", false); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_assert((git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE) != 0); + + /* 1 - add 0644 over existing 0644 -> expect 0644 */ + replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644); + add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB); + + /* 2 - add 0644 over existing 0755 -> expect 0755 */ + replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644); + add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE); + + /* 3 - add 0755 over existing 0644 -> expect 0644 */ + replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755); + add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB); + + /* 4 - add 0755 over existing 0755 -> expect 0755 */ + replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755); + add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE); + + /* 5 - add new 0644 -> expect 0644 */ + cl_git_write2file("filemodes/new_off", "blah", 0, + O_WRONLY | O_CREAT | O_TRUNC, 0644); + add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB); + + /* 6 - add new 0755 -> expect 0644 if core.filemode == false */ + cl_git_write2file("filemodes/new_on", "blah", 0, + O_WRONLY | O_CREAT | O_TRUNC, 0755); + add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB); + + git_index_free(index); +} + +void test_index_filemodes__trusted(void) +{ + git_index *index; + + /* Only run these tests on platforms where I can actually + * chmod a file and get the stat results I expect! + */ + if (!cl_is_chmod_supported()) + return; + + cl_repo_set_bool(g_repo, "core.filemode", true); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_assert((git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE) == 0); + + /* 1 - add 0644 over existing 0644 -> expect 0644 */ + replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644); + add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB); + + /* 2 - add 0644 over existing 0755 -> expect 0644 */ + replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644); + add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB); + + /* 3 - add 0755 over existing 0644 -> expect 0755 */ + replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755); + add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB_EXECUTABLE); + + /* 4 - add 0755 over existing 0755 -> expect 0755 */ + replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755); + add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE); + + /* 5 - add new 0644 -> expect 0644 */ + cl_git_write2file("filemodes/new_off", "blah", 0, + O_WRONLY | O_CREAT | O_TRUNC, 0644); + add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB); + + /* 6 - add 0755 -> expect 0755 */ + cl_git_write2file("filemodes/new_on", "blah", 0, + O_WRONLY | O_CREAT | O_TRUNC, 0755); + add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE); + + git_index_free(index); +} diff --git a/tests/index/inmemory.c b/tests/index/inmemory.c new file mode 100644 index 000000000..38e91e0fd --- /dev/null +++ b/tests/index/inmemory.c @@ -0,0 +1,22 @@ +#include "clar_libgit2.h" + +void test_index_inmemory__can_create_an_inmemory_index(void) +{ + git_index *index; + + cl_git_pass(git_index_new(&index)); + cl_assert_equal_i(0, (int)git_index_entrycount(index)); + + git_index_free(index); +} + +void test_index_inmemory__cannot_add_bypath_to_an_inmemory_index(void) +{ + git_index *index; + + cl_git_pass(git_index_new(&index)); + + cl_assert_equal_i(GIT_ERROR, git_index_add_bypath(index, "test.txt")); + + git_index_free(index); +} diff --git a/tests/index/names.c b/tests/index/names.c new file mode 100644 index 000000000..9007b1b15 --- /dev/null +++ b/tests/index/names.c @@ -0,0 +1,148 @@ +#include "clar_libgit2.h" +#include "index.h" +#include "git2/sys/index.h" +#include "git2/repository.h" +#include "../reset/reset_helpers.h" + +static git_repository *repo; +static git_index *repo_index; + +#define TEST_REPO_PATH "mergedrepo" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + +// Fixture setup and teardown +void test_index_names__initialize(void) +{ + repo = cl_git_sandbox_init("mergedrepo"); + git_repository_index(&repo_index, repo); +} + +void test_index_names__cleanup(void) +{ + git_index_free(repo_index); + repo_index = NULL; + + cl_git_sandbox_cleanup(); +} + +void test_index_names__add(void) +{ + const git_index_name_entry *conflict_name; + + cl_git_pass(git_index_name_add(repo_index, "ancestor", "ours", "theirs")); + cl_git_pass(git_index_name_add(repo_index, "ancestor2", "ours2", NULL)); + cl_git_pass(git_index_name_add(repo_index, "ancestor3", NULL, "theirs3")); + + cl_assert(git_index_name_entrycount(repo_index) == 3); + + conflict_name = git_index_name_get_byindex(repo_index, 0); + cl_assert(strcmp(conflict_name->ancestor, "ancestor") == 0); + cl_assert(strcmp(conflict_name->ours, "ours") == 0); + cl_assert(strcmp(conflict_name->theirs, "theirs") == 0); + + conflict_name = git_index_name_get_byindex(repo_index, 1); + cl_assert(strcmp(conflict_name->ancestor, "ancestor2") == 0); + cl_assert(strcmp(conflict_name->ours, "ours2") == 0); + cl_assert(conflict_name->theirs == NULL); + + conflict_name = git_index_name_get_byindex(repo_index, 2); + cl_assert(strcmp(conflict_name->ancestor, "ancestor3") == 0); + cl_assert(conflict_name->ours == NULL); + cl_assert(strcmp(conflict_name->theirs, "theirs3") == 0); +} + +void test_index_names__roundtrip(void) +{ + const git_index_name_entry *conflict_name; + + cl_git_pass(git_index_name_add(repo_index, "ancestor", "ours", "theirs")); + cl_git_pass(git_index_name_add(repo_index, "ancestor2", "ours2", NULL)); + cl_git_pass(git_index_name_add(repo_index, "ancestor3", NULL, "theirs3")); + + cl_git_pass(git_index_write(repo_index)); + git_index_clear(repo_index); + cl_assert(git_index_name_entrycount(repo_index) == 0); + + cl_git_pass(git_index_read(repo_index, true)); + cl_assert(git_index_name_entrycount(repo_index) == 3); + + conflict_name = git_index_name_get_byindex(repo_index, 0); + cl_assert(strcmp(conflict_name->ancestor, "ancestor") == 0); + cl_assert(strcmp(conflict_name->ours, "ours") == 0); + cl_assert(strcmp(conflict_name->theirs, "theirs") == 0); + + conflict_name = git_index_name_get_byindex(repo_index, 1); + cl_assert(strcmp(conflict_name->ancestor, "ancestor2") == 0); + cl_assert(strcmp(conflict_name->ours, "ours2") == 0); + cl_assert(conflict_name->theirs == NULL); + + conflict_name = git_index_name_get_byindex(repo_index, 2); + cl_assert(strcmp(conflict_name->ancestor, "ancestor3") == 0); + cl_assert(conflict_name->ours == NULL); + cl_assert(strcmp(conflict_name->theirs, "theirs3") == 0); +} + +void test_index_names__cleaned_on_reset_hard(void) +{ + git_object *target; + + retrieve_target_from_oid(&target, repo, "3a34580a35add43a4cf361e8e9a30060a905c876"); + + test_index_names__add(); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD)); + cl_assert(git_index_name_entrycount(repo_index) == 0); + + git_object_free(target); +} + +void test_index_names__cleaned_on_reset_mixed(void) +{ + git_object *target; + + retrieve_target_from_oid(&target, repo, "3a34580a35add43a4cf361e8e9a30060a905c876"); + + test_index_names__add(); + cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED)); + cl_assert(git_index_name_entrycount(repo_index) == 0); + + git_object_free(target); +} + +void test_index_names__cleaned_on_checkout_tree(void) +{ + git_oid oid; + git_object *obj; + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + + opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; + + test_index_names__add(); + git_reference_name_to_id(&oid, repo, "refs/heads/master"); + git_object_lookup(&obj, repo, &oid, GIT_OBJ_ANY); + git_checkout_tree(repo, obj, &opts); + cl_assert_equal_sz(0, git_index_name_entrycount(repo_index)); + + git_object_free(obj); +} + +void test_index_names__cleaned_on_checkout_head(void) +{ + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + + opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; + + test_index_names__add(); + git_checkout_head(repo, &opts); + cl_assert_equal_sz(0, git_index_name_entrycount(repo_index)); +} + +void test_index_names__retained_on_checkout_index(void) +{ + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + + opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; + + test_index_names__add(); + git_checkout_index(repo, repo_index, &opts); + cl_assert(git_index_name_entrycount(repo_index) > 0); +} diff --git a/tests/index/read_tree.c b/tests/index/read_tree.c new file mode 100644 index 000000000..6c6b40121 --- /dev/null +++ b/tests/index/read_tree.c @@ -0,0 +1,46 @@ +#include "clar_libgit2.h" +#include "posix.h" + +/* Test that reading and writing a tree is a no-op */ +void test_index_read_tree__read_write_involution(void) +{ + git_repository *repo; + git_index *index; + git_oid tree_oid; + git_tree *tree; + git_oid expected; + + p_mkdir("read_tree", 0700); + + cl_git_pass(git_repository_init(&repo, "./read_tree", 0)); + cl_git_pass(git_repository_index(&index, repo)); + + cl_assert(git_index_entrycount(index) == 0); + + p_mkdir("./read_tree/abc", 0700); + + /* Sort order: '-' < '/' < '_' */ + cl_git_mkfile("./read_tree/abc-d", NULL); + cl_git_mkfile("./read_tree/abc/d", NULL); + cl_git_mkfile("./read_tree/abc_d", NULL); + + cl_git_pass(git_index_add_bypath(index, "abc-d")); + cl_git_pass(git_index_add_bypath(index, "abc_d")); + cl_git_pass(git_index_add_bypath(index, "abc/d")); + + /* write-tree */ + cl_git_pass(git_index_write_tree(&expected, index)); + + /* read-tree */ + git_tree_lookup(&tree, repo, &expected); + cl_git_pass(git_index_read_tree(index, tree)); + git_tree_free(tree); + + cl_git_pass(git_index_write_tree(&tree_oid, index)); + cl_assert(git_oid_cmp(&expected, &tree_oid) == 0); + + git_index_free(index); + git_repository_free(repo); + + cl_fixture_cleanup("read_tree"); +} diff --git a/tests/index/rename.c b/tests/index/rename.c new file mode 100644 index 000000000..4deef1332 --- /dev/null +++ b/tests/index/rename.c @@ -0,0 +1,50 @@ +#include "clar_libgit2.h" +#include "posix.h" + +void test_index_rename__single_file(void) +{ + git_repository *repo; + git_index *index; + size_t position; + git_oid expected; + const git_index_entry *entry; + + p_mkdir("rename", 0700); + + cl_git_pass(git_repository_init(&repo, "./rename", 0)); + cl_git_pass(git_repository_index(&index, repo)); + + cl_assert(git_index_entrycount(index) == 0); + + cl_git_mkfile("./rename/lame.name.txt", "new_file\n"); + + /* This should add a new blob to the object database in 'd4/fa8600b4f37d7516bef4816ae2c64dbf029e3a' */ + cl_git_pass(git_index_add_bypath(index, "lame.name.txt")); + cl_assert(git_index_entrycount(index) == 1); + + cl_git_pass(git_oid_fromstr(&expected, "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a")); + + cl_assert(!git_index_find(&position, index, "lame.name.txt")); + + entry = git_index_get_byindex(index, position); + cl_assert(git_oid_cmp(&expected, &entry->oid) == 0); + + /* This removes the entry from the index, but not from the object database */ + cl_git_pass(git_index_remove(index, "lame.name.txt", 0)); + cl_assert(git_index_entrycount(index) == 0); + + p_rename("./rename/lame.name.txt", "./rename/fancy.name.txt"); + + cl_git_pass(git_index_add_bypath(index, "fancy.name.txt")); + cl_assert(git_index_entrycount(index) == 1); + + cl_assert(!git_index_find(&position, index, "fancy.name.txt")); + + entry = git_index_get_byindex(index, position); + cl_assert(git_oid_cmp(&expected, &entry->oid) == 0); + + git_index_free(index); + git_repository_free(repo); + + cl_fixture_cleanup("rename"); +} diff --git a/tests/index/reuc.c b/tests/index/reuc.c new file mode 100644 index 000000000..a18d5602e --- /dev/null +++ b/tests/index/reuc.c @@ -0,0 +1,372 @@ +#include "clar_libgit2.h" +#include "index.h" +#include "git2/sys/index.h" +#include "git2/repository.h" +#include "../reset/reset_helpers.h" + +static git_repository *repo; +static git_index *repo_index; + +#define TEST_REPO_PATH "mergedrepo" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + +#define ONE_ANCESTOR_OID "478871385b9cd03908c5383acfd568bef023c6b3" +#define ONE_OUR_OID "4458b8bc9e72b6c8755ae456f60e9844d0538d8c" +#define ONE_THEIR_OID "8b72416545c7e761b64cecad4f1686eae4078aa8" + +#define TWO_ANCESTOR_OID "9d81f82fccc7dcd7de7a1ffead1815294c2e092c" +#define TWO_OUR_OID "8f3c06cff9a83757cec40c80bc9bf31a2582bde9" +#define TWO_THEIR_OID "887b153b165d32409c70163e0f734c090f12f673" + +// Fixture setup and teardown +void test_index_reuc__initialize(void) +{ + repo = cl_git_sandbox_init("mergedrepo"); + git_repository_index(&repo_index, repo); +} + +void test_index_reuc__cleanup(void) +{ + git_index_free(repo_index); + repo_index = NULL; + + cl_git_sandbox_cleanup(); +} + +void test_index_reuc__add(void) +{ + git_oid ancestor_oid, our_oid, their_oid; + const git_index_reuc_entry *reuc; + + git_oid_fromstr(&ancestor_oid, ONE_ANCESTOR_OID); + git_oid_fromstr(&our_oid, ONE_OUR_OID); + git_oid_fromstr(&their_oid, ONE_THEIR_OID); + + cl_git_pass(git_index_reuc_add(repo_index, "newfile.txt", + 0100644, &ancestor_oid, + 0100644, &our_oid, + 0100644, &their_oid)); + + cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "newfile.txt")); + + cl_assert_equal_s("newfile.txt", reuc->path); + cl_assert(reuc->mode[0] == 0100644); + cl_assert(reuc->mode[1] == 0100644); + cl_assert(reuc->mode[2] == 0100644); + cl_assert(git_oid_cmp(&reuc->oid[0], &ancestor_oid) == 0); + cl_assert(git_oid_cmp(&reuc->oid[1], &our_oid) == 0); + cl_assert(git_oid_cmp(&reuc->oid[2], &their_oid) == 0); +} + +void test_index_reuc__add_no_ancestor(void) +{ + git_oid ancestor_oid, our_oid, their_oid; + const git_index_reuc_entry *reuc; + + memset(&ancestor_oid, 0x0, sizeof(git_oid)); + git_oid_fromstr(&our_oid, ONE_OUR_OID); + git_oid_fromstr(&their_oid, ONE_THEIR_OID); + + cl_git_pass(git_index_reuc_add(repo_index, "newfile.txt", + 0, NULL, + 0100644, &our_oid, + 0100644, &their_oid)); + + cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "newfile.txt")); + + cl_assert_equal_s("newfile.txt", reuc->path); + cl_assert(reuc->mode[0] == 0); + cl_assert(reuc->mode[1] == 0100644); + cl_assert(reuc->mode[2] == 0100644); + cl_assert(git_oid_cmp(&reuc->oid[0], &ancestor_oid) == 0); + cl_assert(git_oid_cmp(&reuc->oid[1], &our_oid) == 0); + cl_assert(git_oid_cmp(&reuc->oid[2], &their_oid) == 0); +} + +void test_index_reuc__read_bypath(void) +{ + const git_index_reuc_entry *reuc; + git_oid oid; + + cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); + + cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "two.txt")); + + cl_assert_equal_s("two.txt", reuc->path); + cl_assert(reuc->mode[0] == 0100644); + cl_assert(reuc->mode[1] == 0100644); + cl_assert(reuc->mode[2] == 0100644); + git_oid_fromstr(&oid, TWO_ANCESTOR_OID); + cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); + git_oid_fromstr(&oid, TWO_OUR_OID); + cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); + git_oid_fromstr(&oid, TWO_THEIR_OID); + cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); + + cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "one.txt")); + + cl_assert_equal_s("one.txt", reuc->path); + cl_assert(reuc->mode[0] == 0100644); + cl_assert(reuc->mode[1] == 0100644); + cl_assert(reuc->mode[2] == 0100644); + git_oid_fromstr(&oid, ONE_ANCESTOR_OID); + cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); + git_oid_fromstr(&oid, ONE_OUR_OID); + cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); + git_oid_fromstr(&oid, ONE_THEIR_OID); + cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); +} + +void test_index_reuc__ignore_case(void) +{ + const git_index_reuc_entry *reuc; + git_oid oid; + int index_caps; + + index_caps = git_index_caps(repo_index); + + index_caps &= ~GIT_INDEXCAP_IGNORE_CASE; + cl_git_pass(git_index_set_caps(repo_index, index_caps)); + + cl_assert(!git_index_reuc_get_bypath(repo_index, "TWO.txt")); + + index_caps |= GIT_INDEXCAP_IGNORE_CASE; + cl_git_pass(git_index_set_caps(repo_index, index_caps)); + + cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); + + cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "TWO.txt")); + + cl_assert_equal_s("two.txt", reuc->path); + cl_assert(reuc->mode[0] == 0100644); + cl_assert(reuc->mode[1] == 0100644); + cl_assert(reuc->mode[2] == 0100644); + git_oid_fromstr(&oid, TWO_ANCESTOR_OID); + cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); + git_oid_fromstr(&oid, TWO_OUR_OID); + cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); + git_oid_fromstr(&oid, TWO_THEIR_OID); + cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); +} + +void test_index_reuc__read_byindex(void) +{ + const git_index_reuc_entry *reuc; + git_oid oid; + + cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); + + cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0)); + + cl_assert_equal_s("one.txt", reuc->path); + cl_assert(reuc->mode[0] == 0100644); + cl_assert(reuc->mode[1] == 0100644); + cl_assert(reuc->mode[2] == 0100644); + git_oid_fromstr(&oid, ONE_ANCESTOR_OID); + cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); + git_oid_fromstr(&oid, ONE_OUR_OID); + cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); + git_oid_fromstr(&oid, ONE_THEIR_OID); + cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); + + cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 1)); + + cl_assert_equal_s("two.txt", reuc->path); + cl_assert(reuc->mode[0] == 0100644); + cl_assert(reuc->mode[1] == 0100644); + cl_assert(reuc->mode[2] == 0100644); + git_oid_fromstr(&oid, TWO_ANCESTOR_OID); + cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); + git_oid_fromstr(&oid, TWO_OUR_OID); + cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); + git_oid_fromstr(&oid, TWO_THEIR_OID); + cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); +} + +void test_index_reuc__updates_existing(void) +{ + const git_index_reuc_entry *reuc; + git_oid ancestor_oid, our_oid, their_oid, oid; + int index_caps; + + git_index_clear(repo_index); + + index_caps = git_index_caps(repo_index); + + index_caps |= GIT_INDEXCAP_IGNORE_CASE; + cl_git_pass(git_index_set_caps(repo_index, index_caps)); + + git_oid_fromstr(&ancestor_oid, TWO_ANCESTOR_OID); + git_oid_fromstr(&our_oid, TWO_OUR_OID); + git_oid_fromstr(&their_oid, TWO_THEIR_OID); + + cl_git_pass(git_index_reuc_add(repo_index, "two.txt", + 0100644, &ancestor_oid, + 0100644, &our_oid, + 0100644, &their_oid)); + + cl_git_pass(git_index_reuc_add(repo_index, "TWO.txt", + 0100644, &our_oid, + 0100644, &their_oid, + 0100644, &ancestor_oid)); + + cl_assert_equal_i(1, git_index_reuc_entrycount(repo_index)); + + cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0)); + + cl_assert_equal_s("TWO.txt", reuc->path); + git_oid_fromstr(&oid, TWO_OUR_OID); + cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); + git_oid_fromstr(&oid, TWO_THEIR_OID); + cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); + git_oid_fromstr(&oid, TWO_ANCESTOR_OID); + cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); +} + +void test_index_reuc__remove(void) +{ + git_oid oid; + const git_index_reuc_entry *reuc; + + cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); + + cl_git_pass(git_index_reuc_remove(repo_index, 0)); + cl_git_fail(git_index_reuc_remove(repo_index, 1)); + + cl_assert_equal_i(1, git_index_reuc_entrycount(repo_index)); + + cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0)); + + cl_assert_equal_s("two.txt", reuc->path); + cl_assert(reuc->mode[0] == 0100644); + cl_assert(reuc->mode[1] == 0100644); + cl_assert(reuc->mode[2] == 0100644); + git_oid_fromstr(&oid, TWO_ANCESTOR_OID); + cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); + git_oid_fromstr(&oid, TWO_OUR_OID); + cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); + git_oid_fromstr(&oid, TWO_THEIR_OID); + cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); +} + +void test_index_reuc__write(void) +{ + git_oid ancestor_oid, our_oid, their_oid; + const git_index_reuc_entry *reuc; + + git_index_clear(repo_index); + + /* Write out of order to ensure sorting is correct */ + git_oid_fromstr(&ancestor_oid, TWO_ANCESTOR_OID); + git_oid_fromstr(&our_oid, TWO_OUR_OID); + git_oid_fromstr(&their_oid, TWO_THEIR_OID); + + cl_git_pass(git_index_reuc_add(repo_index, "two.txt", + 0100644, &ancestor_oid, + 0100644, &our_oid, + 0100644, &their_oid)); + + git_oid_fromstr(&ancestor_oid, ONE_ANCESTOR_OID); + git_oid_fromstr(&our_oid, ONE_OUR_OID); + git_oid_fromstr(&their_oid, ONE_THEIR_OID); + + cl_git_pass(git_index_reuc_add(repo_index, "one.txt", + 0100644, &ancestor_oid, + 0100644, &our_oid, + 0100644, &their_oid)); + + cl_git_pass(git_index_write(repo_index)); + cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); + + /* ensure sort order was round-tripped correct */ + cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0)); + cl_assert_equal_s("one.txt", reuc->path); + + cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 1)); + cl_assert_equal_s("two.txt", reuc->path); +} + +static int reuc_entry_exists(void) +{ + return (git_index_reuc_get_bypath(repo_index, "newfile.txt") != NULL); +} + +void test_index_reuc__cleaned_on_reset_hard(void) +{ + git_object *target; + + retrieve_target_from_oid(&target, repo, "3a34580a35add43a4cf361e8e9a30060a905c876"); + + test_index_reuc__add(); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD)); + cl_assert(reuc_entry_exists() == false); + + git_object_free(target); +} + +void test_index_reuc__cleaned_on_reset_mixed(void) +{ + git_object *target; + + retrieve_target_from_oid(&target, repo, "3a34580a35add43a4cf361e8e9a30060a905c876"); + + test_index_reuc__add(); + cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED)); + cl_assert(reuc_entry_exists() == false); + + git_object_free(target); +} + +void test_index_reuc__retained_on_reset_soft(void) +{ + git_object *target; + + retrieve_target_from_oid(&target, repo, "3a34580a35add43a4cf361e8e9a30060a905c876"); + + git_reset(repo, target, GIT_RESET_HARD); + + test_index_reuc__add(); + cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT)); + cl_assert(reuc_entry_exists() == true); + + git_object_free(target); +} + +void test_index_reuc__cleaned_on_checkout_tree(void) +{ + git_oid oid; + git_object *obj; + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + + opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; + + test_index_reuc__add(); + git_reference_name_to_id(&oid, repo, "refs/heads/master"); + git_object_lookup(&obj, repo, &oid, GIT_OBJ_ANY); + git_checkout_tree(repo, obj, &opts); + cl_assert(reuc_entry_exists() == false); + + git_object_free(obj); +} + +void test_index_reuc__cleaned_on_checkout_head(void) +{ + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + + opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; + + test_index_reuc__add(); + git_checkout_head(repo, &opts); + cl_assert(reuc_entry_exists() == false); +} + +void test_index_reuc__retained_on_checkout_index(void) +{ + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + + opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; + + test_index_reuc__add(); + git_checkout_index(repo, repo_index, &opts); + cl_assert(reuc_entry_exists() == true); +} diff --git a/tests/index/stage.c b/tests/index/stage.c new file mode 100644 index 000000000..58dc1fb5e --- /dev/null +++ b/tests/index/stage.c @@ -0,0 +1,62 @@ +#include "clar_libgit2.h" +#include "index.h" +#include "git2/repository.h" + +static git_repository *repo; +static git_index *repo_index; + +#define TEST_REPO_PATH "mergedrepo" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + +// Fixture setup and teardown +void test_index_stage__initialize(void) +{ + repo = cl_git_sandbox_init("mergedrepo"); + git_repository_index(&repo_index, repo); +} + +void test_index_stage__cleanup(void) +{ + git_index_free(repo_index); + repo_index = NULL; + + cl_git_sandbox_cleanup(); +} + + +void test_index_stage__add_always_adds_stage_0(void) +{ + size_t entry_idx; + const git_index_entry *entry; + + cl_git_mkfile("./mergedrepo/new-file.txt", "new-file\n"); + + cl_git_pass(git_index_add_bypath(repo_index, "new-file.txt")); + + cl_assert(!git_index_find(&entry_idx, repo_index, "new-file.txt")); + cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); + cl_assert(git_index_entry_stage(entry) == 0); +} + +void test_index_stage__find_gets_first_stage(void) +{ + size_t entry_idx; + const git_index_entry *entry; + + cl_assert(!git_index_find(&entry_idx, repo_index, "one.txt")); + cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); + cl_assert(git_index_entry_stage(entry) == 0); + + cl_assert(!git_index_find(&entry_idx, repo_index, "two.txt")); + cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); + cl_assert(git_index_entry_stage(entry) == 0); + + cl_assert(!git_index_find(&entry_idx, repo_index, "conflicts-one.txt")); + cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); + cl_assert(git_index_entry_stage(entry) == 1); + + cl_assert(!git_index_find(&entry_idx, repo_index, "conflicts-two.txt")); + cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); + cl_assert(git_index_entry_stage(entry) == 1); +} + diff --git a/tests/index/tests.c b/tests/index/tests.c new file mode 100644 index 000000000..e5202980c --- /dev/null +++ b/tests/index/tests.c @@ -0,0 +1,537 @@ +#include "clar_libgit2.h" +#include "index.h" + +static const size_t index_entry_count = 109; +static const size_t index_entry_count_2 = 1437; +#define TEST_INDEX_PATH cl_fixture("testrepo.git/index") +#define TEST_INDEX2_PATH cl_fixture("gitgit.index") +#define TEST_INDEXBIG_PATH cl_fixture("big.index") + + +/* Suite data */ +struct test_entry { + size_t index; + char path[128]; + git_off_t file_size; + git_time_t mtime; +}; + +static struct test_entry test_entries[] = { + {4, "Makefile", 5064, 0x4C3F7F33}, + {62, "tests/Makefile", 2631, 0x4C3F7F33}, + {36, "src/index.c", 10014, 0x4C43368D}, + {6, "git.git-authors", 2709, 0x4C3F7F33}, + {48, "src/revobject.h", 1448, 0x4C3F7FE2} +}; + +/* Helpers */ +static void copy_file(const char *src, const char *dst) +{ + git_buf source_buf = GIT_BUF_INIT; + git_file dst_fd; + + cl_git_pass(git_futils_readbuffer(&source_buf, src)); + + dst_fd = git_futils_creat_withpath(dst, 0777, 0666); /* -V536 */ + if (dst_fd < 0) + goto cleanup; + + cl_git_pass(p_write(dst_fd, source_buf.ptr, source_buf.size)); + +cleanup: + git_buf_free(&source_buf); + p_close(dst_fd); +} + +static void files_are_equal(const char *a, const char *b) +{ + git_buf buf_a = GIT_BUF_INIT; + git_buf buf_b = GIT_BUF_INIT; + int pass; + + if (git_futils_readbuffer(&buf_a, a) < 0) + cl_assert(0); + + if (git_futils_readbuffer(&buf_b, b) < 0) { + git_buf_free(&buf_a); + cl_assert(0); + } + + pass = (buf_a.size == buf_b.size && !memcmp(buf_a.ptr, buf_b.ptr, buf_a.size)); + + git_buf_free(&buf_a); + git_buf_free(&buf_b); + + cl_assert(pass); +} + + +/* Fixture setup and teardown */ +void test_index_tests__initialize(void) +{ +} + +void test_index_tests__empty_index(void) +{ + git_index *index; + + cl_git_pass(git_index_open(&index, "in-memory-index")); + cl_assert(index->on_disk == 0); + + cl_assert(git_index_entrycount(index) == 0); + cl_assert(index->entries.sorted); + + git_index_free(index); +} + +void test_index_tests__default_test_index(void) +{ + git_index *index; + unsigned int i; + git_index_entry **entries; + + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + cl_assert(index->on_disk); + + cl_assert(git_index_entrycount(index) == index_entry_count); + cl_assert(index->entries.sorted); + + entries = (git_index_entry **)index->entries.contents; + + for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { + git_index_entry *e = entries[test_entries[i].index]; + + cl_assert_equal_s(e->path, test_entries[i].path); + cl_assert(e->mtime.seconds == test_entries[i].mtime); + cl_assert(e->file_size == test_entries[i].file_size); + } + + git_index_free(index); +} + +void test_index_tests__gitgit_index(void) +{ + git_index *index; + + cl_git_pass(git_index_open(&index, TEST_INDEX2_PATH)); + cl_assert(index->on_disk); + + cl_assert(git_index_entrycount(index) == index_entry_count_2); + cl_assert(index->entries.sorted); + cl_assert(index->tree != NULL); + + git_index_free(index); +} + +void test_index_tests__find_in_existing(void) +{ + git_index *index; + unsigned int i; + + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + + for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { + size_t idx; + + cl_assert(!git_index_find(&idx, index, test_entries[i].path)); + cl_assert(idx == test_entries[i].index); + } + + git_index_free(index); +} + +void test_index_tests__find_in_empty(void) +{ + git_index *index; + unsigned int i; + + cl_git_pass(git_index_open(&index, "fake-index")); + + for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { + cl_assert(GIT_ENOTFOUND == git_index_find(NULL, index, test_entries[i].path)); + } + + git_index_free(index); +} + +void test_index_tests__write(void) +{ + git_index *index; + + copy_file(TEST_INDEXBIG_PATH, "index_rewrite"); + + cl_git_pass(git_index_open(&index, "index_rewrite")); + cl_assert(index->on_disk); + + cl_git_pass(git_index_write(index)); + files_are_equal(TEST_INDEXBIG_PATH, "index_rewrite"); + + git_index_free(index); + + p_unlink("index_rewrite"); +} + +void test_index_tests__sort0(void) +{ + /* sort the entires in an index */ + + /* + * TODO: This no longer applies: + * index sorting in Git uses some specific changes to the way + * directories are sorted. + * + * We need to specificially check for this by creating a new + * index, adding entries in random order and then + * checking for consistency + */ +} + +void test_index_tests__sort1(void) +{ + /* sort the entires in an empty index */ + git_index *index; + + cl_git_pass(git_index_open(&index, "fake-index")); + + /* FIXME: this test is slightly dumb */ + cl_assert(index->entries.sorted); + + git_index_free(index); +} + +static void cleanup_myrepo(void *opaque) +{ + GIT_UNUSED(opaque); + cl_fixture_cleanup("myrepo"); +} + +void test_index_tests__add(void) +{ + git_index *index; + git_filebuf file = GIT_FILEBUF_INIT; + git_repository *repo; + const git_index_entry *entry; + git_oid id1; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + /* Intialize a new repository */ + cl_git_pass(git_repository_init(&repo, "./myrepo", 0)); + + /* Ensure we're the only guy in the room */ + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(git_index_entrycount(index) == 0); + + /* Create a new file in the working directory */ + cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777)); + cl_git_pass(git_filebuf_open(&file, "myrepo/test.txt", 0, 0666)); + cl_git_pass(git_filebuf_write(&file, "hey there\n", 10)); + cl_git_pass(git_filebuf_commit(&file)); + + /* Store the expected hash of the file/blob + * This has been generated by executing the following + * $ echo "hey there" | git hash-object --stdin + */ + cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6")); + + /* Add the new file to the index */ + cl_git_pass(git_index_add_bypath(index, "test.txt")); + + /* Wow... it worked! */ + cl_assert(git_index_entrycount(index) == 1); + entry = git_index_get_byindex(index, 0); + + /* And the built-in hashing mechanism worked as expected */ + cl_assert(git_oid_cmp(&id1, &entry->oid) == 0); + + /* Test access by path instead of index */ + cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); + cl_assert(git_oid_cmp(&id1, &entry->oid) == 0); + + git_index_free(index); + git_repository_free(repo); +} + +static void cleanup_1397(void *opaque) +{ + GIT_UNUSED(opaque); + cl_git_sandbox_cleanup(); +} + +void test_index_tests__add_issue_1397(void) +{ + git_index *index; + git_repository *repo; + const git_index_entry *entry; + git_oid id1; + + cl_set_cleanup(&cleanup_1397, NULL); + + repo = cl_git_sandbox_init("issue_1397"); + + cl_repo_set_bool(repo, "core.autocrlf", true); + + /* Ensure we're the only guy in the room */ + cl_git_pass(git_repository_index(&index, repo)); + + /* Store the expected hash of the file/blob + * This has been generated by executing the following + * $ git hash-object crlf_file.txt + */ + cl_git_pass(git_oid_fromstr(&id1, "8312e0889a9cbab77c732b6bc39b51a683e3a318")); + + /* Make sure the initial SHA-1 is correct */ + cl_assert((entry = git_index_get_bypath(index, "crlf_file.txt", 0)) != NULL); + cl_assert_(git_oid_cmp(&id1, &entry->oid) == 0, "first oid check"); + + /* Update the index */ + cl_git_pass(git_index_add_bypath(index, "crlf_file.txt")); + + /* Check the new SHA-1 */ + cl_assert((entry = git_index_get_bypath(index, "crlf_file.txt", 0)) != NULL); + cl_assert_(git_oid_cmp(&id1, &entry->oid) == 0, "second oid check"); + + git_index_free(index); +} + +void test_index_tests__add_bypath_to_a_bare_repository_returns_EBAREPO(void) +{ + git_repository *bare_repo; + git_index *index; + + cl_git_pass(git_repository_open(&bare_repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_index(&index, bare_repo)); + + cl_assert_equal_i(GIT_EBAREREPO, git_index_add_bypath(index, "test.txt")); + + git_index_free(index); + git_repository_free(bare_repo); +} + +/* Test that writing an invalid filename fails */ +void test_index_tests__write_invalid_filename(void) +{ + git_repository *repo; + git_index *index; + git_oid expected; + + p_mkdir("read_tree", 0700); + + cl_git_pass(git_repository_init(&repo, "./read_tree", 0)); + cl_git_pass(git_repository_index(&index, repo)); + + cl_assert(git_index_entrycount(index) == 0); + + cl_git_mkfile("./read_tree/.git/hello", NULL); + + cl_git_pass(git_index_add_bypath(index, ".git/hello")); + + /* write-tree */ + cl_git_fail(git_index_write_tree(&expected, index)); + + git_index_free(index); + git_repository_free(repo); + + cl_fixture_cleanup("read_tree"); +} + +void test_index_tests__remove_entry(void) +{ + git_repository *repo; + git_index *index; + + p_mkdir("index_test", 0770); + + cl_git_pass(git_repository_init(&repo, "index_test", 0)); + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(git_index_entrycount(index) == 0); + + cl_git_mkfile("index_test/hello", NULL); + cl_git_pass(git_index_add_bypath(index, "hello")); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert(git_index_entrycount(index) == 1); + cl_assert(git_index_get_bypath(index, "hello", 0) != NULL); + + cl_git_pass(git_index_remove(index, "hello", 0)); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert(git_index_entrycount(index) == 0); + cl_assert(git_index_get_bypath(index, "hello", 0) == NULL); + + git_index_free(index); + git_repository_free(repo); + cl_fixture_cleanup("index_test"); +} + +void test_index_tests__remove_directory(void) +{ + git_repository *repo; + git_index *index; + + p_mkdir("index_test", 0770); + + cl_git_pass(git_repository_init(&repo, "index_test", 0)); + cl_git_pass(git_repository_index(&index, repo)); + cl_assert_equal_i(0, (int)git_index_entrycount(index)); + + p_mkdir("index_test/a", 0770); + cl_git_mkfile("index_test/a/1.txt", NULL); + cl_git_mkfile("index_test/a/2.txt", NULL); + cl_git_mkfile("index_test/a/3.txt", NULL); + cl_git_mkfile("index_test/b.txt", NULL); + + cl_git_pass(git_index_add_bypath(index, "a/1.txt")); + cl_git_pass(git_index_add_bypath(index, "a/2.txt")); + cl_git_pass(git_index_add_bypath(index, "a/3.txt")); + cl_git_pass(git_index_add_bypath(index, "b.txt")); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert_equal_i(4, (int)git_index_entrycount(index)); + cl_assert(git_index_get_bypath(index, "a/1.txt", 0) != NULL); + cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL); + cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL); + + cl_git_pass(git_index_remove(index, "a/1.txt", 0)); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert_equal_i(3, (int)git_index_entrycount(index)); + cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL); + cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL); + cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL); + + cl_git_pass(git_index_remove_directory(index, "a", 0)); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert_equal_i(1, (int)git_index_entrycount(index)); + cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL); + cl_assert(git_index_get_bypath(index, "a/2.txt", 0) == NULL); + cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL); + + git_index_free(index); + git_repository_free(repo); + cl_fixture_cleanup("index_test"); +} + +void test_index_tests__preserves_case(void) +{ + git_repository *repo; + git_index *index; + const git_index_entry *entry; + int index_caps; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + cl_git_pass(git_repository_init(&repo, "./myrepo", 0)); + cl_git_pass(git_repository_index(&index, repo)); + + index_caps = git_index_caps(index); + + cl_git_rewritefile("myrepo/test.txt", "hey there\n"); + cl_git_pass(git_index_add_bypath(index, "test.txt")); + + cl_git_pass(p_rename("myrepo/test.txt", "myrepo/TEST.txt")); + cl_git_rewritefile("myrepo/TEST.txt", "hello again\n"); + cl_git_pass(git_index_add_bypath(index, "TEST.txt")); + + if (index_caps & GIT_INDEXCAP_IGNORE_CASE) + cl_assert_equal_i(1, (int)git_index_entrycount(index)); + else + cl_assert_equal_i(2, (int)git_index_entrycount(index)); + + /* Test access by path instead of index */ + cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); + /* The path should *not* have changed without an explicit remove */ + cl_assert(git__strcmp(entry->path, "test.txt") == 0); + + cl_assert((entry = git_index_get_bypath(index, "TEST.txt", 0)) != NULL); + if (index_caps & GIT_INDEXCAP_IGNORE_CASE) + /* The path should *not* have changed without an explicit remove */ + cl_assert(git__strcmp(entry->path, "test.txt") == 0); + else + cl_assert(git__strcmp(entry->path, "TEST.txt") == 0); + + git_index_free(index); + git_repository_free(repo); +} + +void test_index_tests__elocked(void) +{ + git_repository *repo; + git_index *index; + git_filebuf file = GIT_FILEBUF_INIT; + const git_error *err; + int error; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + cl_git_pass(git_repository_init(&repo, "./myrepo", 0)); + cl_git_pass(git_repository_index(&index, repo)); + + /* Lock the index file so we fail to lock it */ + cl_git_pass(git_filebuf_open(&file, index->index_file_path, 0, 0666)); + error = git_index_write(index); + cl_assert_equal_i(GIT_ELOCKED, error); + + err = giterr_last(); + cl_assert_equal_i(err->klass, GITERR_INDEX); + + git_filebuf_cleanup(&file); + git_index_free(index); + git_repository_free(repo); +} + +void test_index_tests__reload_from_disk(void) +{ + git_repository *repo; + git_index *read_index; + git_index *write_index; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + cl_git_pass(git_futils_mkdir("./myrepo", NULL, 0777, GIT_MKDIR_PATH)); + cl_git_mkfile("./myrepo/a.txt", "a\n"); + cl_git_mkfile("./myrepo/b.txt", "b\n"); + + cl_git_pass(git_repository_init(&repo, "./myrepo", 0)); + cl_git_pass(git_repository_index(&write_index, repo)); + cl_assert_equal_i(false, write_index->on_disk); + + cl_git_pass(git_index_open(&read_index, write_index->index_file_path)); + cl_assert_equal_i(false, read_index->on_disk); + + /* Stage two new files agaisnt the write_index */ + cl_git_pass(git_index_add_bypath(write_index, "a.txt")); + cl_git_pass(git_index_add_bypath(write_index, "b.txt")); + + cl_assert_equal_sz(2, git_index_entrycount(write_index)); + + /* Persist the index changes to disk */ + cl_git_pass(git_index_write(write_index)); + cl_assert_equal_i(true, write_index->on_disk); + + /* Sync the changes back into the read_index */ + cl_assert_equal_sz(0, git_index_entrycount(read_index)); + + cl_git_pass(git_index_read(read_index, true)); + cl_assert_equal_i(true, read_index->on_disk); + + cl_assert_equal_sz(2, git_index_entrycount(read_index)); + + /* Remove the index file from the filesystem */ + cl_git_pass(p_unlink(write_index->index_file_path)); + + /* Sync the changes back into the read_index */ + cl_git_pass(git_index_read(read_index, true)); + cl_assert_equal_i(false, read_index->on_disk); + cl_assert_equal_sz(0, git_index_entrycount(read_index)); + + git_index_free(read_index); + git_index_free(write_index); + git_repository_free(repo); +} |