Initial commit

This commit is contained in:
jiapengyu
2026-07-27 13:37:48 +08:00
commit ecba71e2a5
39123 changed files with 5989154 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
#include "clar_libgit2.h"
static git_repository *g_repo = NULL;
static git_index *g_index = NULL;
static const char *valid_blob_id = "fa49b077972391ad58037050f2a75f74e3671e92";
static const char *valid_tree_id = "181037049a54a1eb5fab404658a3a250b44335d7";
static const char *valid_commit_id = "763d71aadf09a7951596c9746c024e7eece7c7af";
static const char *invalid_id = "1234567890123456789012345678901234567890";
void test_index_add__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_repository_index(&g_index, g_repo));
}
void test_index_add__cleanup(void)
{
git_index_free(g_index);
cl_git_sandbox_cleanup();
g_repo = NULL;
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1));
}
static void test_add_entry(
bool should_succeed, const char *idstr, git_filemode_t mode)
{
git_index_entry entry = {{0}};
cl_git_pass(git_oid_fromstr(&entry.id, idstr));
entry.path = mode == GIT_FILEMODE_TREE ? "test_folder" : "test_file";
entry.mode = mode;
if (should_succeed)
cl_git_pass(git_index_add(g_index, &entry));
else
cl_git_fail(git_index_add(g_index, &entry));
}
void test_index_add__invalid_entries_succeeds_by_default(void)
{
/*
* Ensure that there is validation on object ids by default
*/
/* ensure that we can add some actually good entries */
test_add_entry(true, valid_blob_id, GIT_FILEMODE_BLOB);
test_add_entry(true, valid_blob_id, GIT_FILEMODE_BLOB_EXECUTABLE);
test_add_entry(true, valid_blob_id, GIT_FILEMODE_LINK);
/* test that we fail to add some invalid (missing) blobs and trees */
test_add_entry(false, invalid_id, GIT_FILEMODE_BLOB);
test_add_entry(false, invalid_id, GIT_FILEMODE_BLOB_EXECUTABLE);
test_add_entry(false, invalid_id, GIT_FILEMODE_LINK);
/* test that we validate the types of objects */
test_add_entry(false, valid_commit_id, GIT_FILEMODE_BLOB);
test_add_entry(false, valid_tree_id, GIT_FILEMODE_BLOB_EXECUTABLE);
test_add_entry(false, valid_commit_id, GIT_FILEMODE_LINK);
/*
* Ensure that there we can disable validation
*/
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0));
/* ensure that we can add some actually good entries */
test_add_entry(true, valid_blob_id, GIT_FILEMODE_BLOB);
test_add_entry(true, valid_blob_id, GIT_FILEMODE_BLOB_EXECUTABLE);
test_add_entry(true, valid_blob_id, GIT_FILEMODE_LINK);
/* test that we can now add some invalid (missing) blobs and trees */
test_add_entry(true, invalid_id, GIT_FILEMODE_BLOB);
test_add_entry(true, invalid_id, GIT_FILEMODE_BLOB_EXECUTABLE);
test_add_entry(true, invalid_id, GIT_FILEMODE_LINK);
/* test that we do not validate the types of objects */
test_add_entry(true, valid_commit_id, GIT_FILEMODE_BLOB);
test_add_entry(true, valid_tree_id, GIT_FILEMODE_BLOB_EXECUTABLE);
test_add_entry(true, valid_commit_id, GIT_FILEMODE_LINK);
}
+498
View File
@@ -0,0 +1,498 @@
#include "clar_libgit2.h"
#include "../status/status_helpers.h"
#include "posix.h"
#include "futils.h"
static git_repository *g_repo = NULL;
#define TEST_DIR "addall"
void test_index_addall__initialize(void)
{
}
void test_index_addall__cleanup(void)
{
cl_git_sandbox_cleanup();
}
#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;
size_t conflicts;
} 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++;
if (status_flags & GIT_STATUS_CONFLICTED)
vals->conflicts++;
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,
size_t conflicts, 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);
clar__assert_equal(
file,line,"wrong conflicts", 1, "%"PRIuZ, conflicts, vals.conflicts);
}
#define check_status(R,IA,ID,IM,WA,WD,WM,IG,C) \
check_status_at_line(R,IA,ID,IM,WA,WD,WM,IG,C,__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((uint32_t)st.st_uid == entry->uid);
cl_assert((uint32_t)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 :( */
}
}
static void addall_create_test_repo(bool check_every_step)
{
g_repo = cl_git_sandbox_init_new(TEST_DIR);
if (check_every_step)
check_status(g_repo, 0, 0, 0, 0, 0, 0, 0, 0);
cl_git_mkfile(TEST_DIR "/file.foo", "a file");
if (check_every_step)
check_status(g_repo, 0, 0, 0, 1, 0, 0, 0, 0);
cl_git_mkfile(TEST_DIR "/.gitignore", "*.foo\n");
if (check_every_step)
check_status(g_repo, 0, 0, 0, 1, 0, 0, 1, 0);
cl_git_mkfile(TEST_DIR "/file.bar", "another file");
if (check_every_step)
check_status(g_repo, 0, 0, 0, 2, 0, 0, 1, 0);
}
void test_index_addall__repo_lifecycle(void)
{
int error;
git_index *index;
git_strarray paths = { NULL, 0 };
char *strs[1];
addall_create_test_repo(true);
cl_git_pass(git_repository_index(&index, g_repo));
strs[0] = "file.*";
paths.strings = strs;
paths.count = 1;
cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_stat_data(index, TEST_DIR "/file.bar", true);
check_status(g_repo, 1, 0, 0, 1, 0, 0, 1, 0);
cl_git_rewritefile(TEST_DIR "/file.bar", "new content for file");
check_stat_data(index, TEST_DIR "/file.bar", false);
check_status(g_repo, 1, 0, 0, 1, 0, 1, 1, 0);
cl_git_mkfile(TEST_DIR "/file.zzz", "yet another one");
cl_git_mkfile(TEST_DIR "/other.zzz", "yet another one");
cl_git_mkfile(TEST_DIR "/more.zzz", "yet another one");
check_status(g_repo, 1, 0, 0, 4, 0, 1, 1, 0);
cl_git_pass(git_index_update_all(index, NULL, NULL, NULL));
check_stat_data(index, TEST_DIR "/file.bar", true);
check_status(g_repo, 1, 0, 0, 4, 0, 0, 1, 0);
cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_stat_data(index, TEST_DIR "/file.zzz", true);
check_status(g_repo, 2, 0, 0, 3, 0, 0, 1, 0);
cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "first commit");
check_status(g_repo, 0, 0, 0, 3, 0, 0, 1, 0);
if (cl_repo_get_bool(g_repo, "core.filemode")) {
cl_git_pass(git_index_update_all(index, NULL, NULL, NULL));
cl_must_pass(p_chmod(TEST_DIR "/file.zzz", 0777));
cl_git_pass(git_index_update_all(index, NULL, NULL, NULL));
check_status(g_repo, 0, 0, 1, 3, 0, 0, 1, 0);
/* go back to what we had before */
cl_must_pass(p_chmod(TEST_DIR "/file.zzz", 0666));
cl_git_pass(git_index_update_all(index, NULL, NULL, NULL));
check_status(g_repo, 0, 0, 0, 3, 0, 0, 1, 0);
}
/* attempt to add an ignored file - does nothing */
strs[0] = "file.foo";
cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_status(g_repo, 0, 0, 0, 3, 0, 0, 1, 0);
/* 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);
cl_git_pass(git_index_write(index));
check_status(g_repo, 0, 0, 0, 3, 0, 0, 1, 0);
/* add with force - should allow */
cl_git_pass(git_index_add_all(
index, &paths, GIT_INDEX_ADD_FORCE, NULL, NULL));
cl_git_pass(git_index_write(index));
check_stat_data(index, TEST_DIR "/file.foo", true);
check_status(g_repo, 1, 0, 0, 3, 0, 0, 0, 0);
/* now it's in the index, so regular add should work */
cl_git_rewritefile(TEST_DIR "/file.foo", "new content for file");
check_stat_data(index, TEST_DIR "/file.foo", false);
check_status(g_repo, 1, 0, 0, 3, 0, 1, 0, 0);
cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_stat_data(index, TEST_DIR "/file.foo", true);
check_status(g_repo, 1, 0, 0, 3, 0, 0, 0, 0);
cl_git_pass(git_index_add_bypath(index, "more.zzz"));
check_stat_data(index, TEST_DIR "/more.zzz", true);
check_status(g_repo, 2, 0, 0, 2, 0, 0, 0, 0);
cl_git_rewritefile(TEST_DIR "/file.zzz", "new content for file");
check_status(g_repo, 2, 0, 0, 2, 0, 1, 0, 0);
cl_git_pass(git_index_add_bypath(index, "file.zzz"));
check_stat_data(index, TEST_DIR "/file.zzz", true);
check_status(g_repo, 2, 0, 1, 2, 0, 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, 0);
cl_git_pass(git_index_add_bypath(index, "file.zzz"));
check_status(g_repo, 1, 0, 1, 3, 0, 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, 0);
cl_must_pass(p_unlink(TEST_DIR "/file.zzz"));
check_status(g_repo, 0, 0, 0, 3, 1, 0, 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, 0);
strs[0] = "*";
cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_status(g_repo, 3, 1, 0, 0, 0, 0, 0, 0);
/* must be able to remove at any position while still updating other files */
cl_must_pass(p_unlink(TEST_DIR "/.gitignore"));
cl_git_rewritefile(TEST_DIR "/file.zzz", "reconstructed file");
cl_git_rewritefile(TEST_DIR "/more.zzz", "altered file reality");
check_status(g_repo, 3, 1, 0, 1, 1, 1, 0, 0);
cl_git_pass(git_index_update_all(index, NULL, NULL, NULL));
check_status(g_repo, 2, 1, 0, 1, 0, 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);
}
void test_index_addall__files_in_folders(void)
{
git_index *index;
addall_create_test_repo(true);
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_add_all(index, NULL, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_stat_data(index, TEST_DIR "/file.bar", true);
check_status(g_repo, 2, 0, 0, 0, 0, 0, 1, 0);
cl_must_pass(p_mkdir(TEST_DIR "/subdir", 0777));
cl_git_mkfile(TEST_DIR "/subdir/file", "hello!\n");
check_status(g_repo, 2, 0, 0, 1, 0, 0, 1, 0);
cl_git_pass(git_index_add_all(index, NULL, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_status(g_repo, 3, 0, 0, 0, 0, 0, 1, 0);
git_index_free(index);
}
void test_index_addall__hidden_files(void)
{
git_index *index;
GIT_UNUSED(index);
#ifdef GIT_WIN32
addall_create_test_repo(true);
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_add_all(index, NULL, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_stat_data(index, TEST_DIR "/file.bar", true);
check_status(g_repo, 2, 0, 0, 0, 0, 0, 1, 0);
cl_git_mkfile(TEST_DIR "/file.zzz", "yet another one");
cl_git_mkfile(TEST_DIR "/more.zzz", "yet another one");
cl_git_mkfile(TEST_DIR "/other.zzz", "yet another one");
check_status(g_repo, 2, 0, 0, 3, 0, 0, 1, 0);
cl_git_pass(git_win32__set_hidden(TEST_DIR "/file.zzz", true));
cl_git_pass(git_win32__set_hidden(TEST_DIR "/more.zzz", true));
cl_git_pass(git_win32__set_hidden(TEST_DIR "/other.zzz", true));
check_status(g_repo, 2, 0, 0, 3, 0, 0, 1, 0);
cl_git_pass(git_index_add_all(index, NULL, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_stat_data(index, TEST_DIR "/file.bar", true);
check_status(g_repo, 5, 0, 0, 0, 0, 0, 1, 0);
git_index_free(index);
#endif
}
static int addall_match_prefix(
const char *path, const char *matched_pathspec, void *payload)
{
GIT_UNUSED(matched_pathspec);
return !git__prefixcmp(path, payload) ? 0 : 1;
}
static int addall_match_suffix(
const char *path, const char *matched_pathspec, void *payload)
{
GIT_UNUSED(matched_pathspec);
return !git__suffixcmp(path, payload) ? 0 : 1;
}
static int addall_cancel_at(
const char *path, const char *matched_pathspec, void *payload)
{
GIT_UNUSED(matched_pathspec);
return !strcmp(path, payload) ? -123 : 0;
}
void test_index_addall__callback_filtering(void)
{
git_index *index;
addall_create_test_repo(false);
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(
git_index_add_all(index, NULL, 0, addall_match_prefix, "file."));
cl_git_pass(git_index_write(index));
check_stat_data(index, TEST_DIR "/file.bar", true);
check_status(g_repo, 1, 0, 0, 1, 0, 0, 1, 0);
cl_git_mkfile(TEST_DIR "/file.zzz", "yet another one");
cl_git_mkfile(TEST_DIR "/more.zzz", "yet another one");
cl_git_mkfile(TEST_DIR "/other.zzz", "yet another one");
cl_git_pass(git_index_update_all(index, NULL, NULL, NULL));
check_stat_data(index, TEST_DIR "/file.bar", true);
check_status(g_repo, 1, 0, 0, 4, 0, 0, 1, 0);
cl_git_pass(
git_index_add_all(index, NULL, 0, addall_match_prefix, "other"));
cl_git_pass(git_index_write(index));
check_stat_data(index, TEST_DIR "/other.zzz", true);
check_status(g_repo, 2, 0, 0, 3, 0, 0, 1, 0);
cl_git_pass(
git_index_add_all(index, NULL, 0, addall_match_suffix, ".zzz"));
cl_git_pass(git_index_write(index));
check_status(g_repo, 4, 0, 0, 1, 0, 0, 1, 0);
cl_git_pass(
git_index_remove_all(index, NULL, addall_match_suffix, ".zzz"));
check_status(g_repo, 1, 0, 0, 4, 0, 0, 1, 0);
cl_git_fail_with(
git_index_add_all(index, NULL, 0, addall_cancel_at, "more.zzz"), -123);
check_status(g_repo, 3, 0, 0, 2, 0, 0, 1, 0);
cl_git_fail_with(
git_index_add_all(index, NULL, 0, addall_cancel_at, "other.zzz"), -123);
check_status(g_repo, 4, 0, 0, 1, 0, 0, 1, 0);
cl_git_pass(
git_index_add_all(index, NULL, 0, addall_match_suffix, ".zzz"));
cl_git_pass(git_index_write(index));
check_status(g_repo, 5, 0, 0, 0, 0, 0, 1, 0);
cl_must_pass(p_unlink(TEST_DIR "/file.zzz"));
cl_must_pass(p_unlink(TEST_DIR "/more.zzz"));
cl_must_pass(p_unlink(TEST_DIR "/other.zzz"));
cl_git_fail_with(
git_index_update_all(index, NULL, addall_cancel_at, "more.zzz"), -123);
/* file.zzz removed from index (so Index Adds 5 -> 4) and
* more.zzz + other.zzz removed (so Worktree Dels 0 -> 2) */
check_status(g_repo, 4, 0, 0, 0, 2, 0, 1, 0);
cl_git_fail_with(
git_index_update_all(index, NULL, addall_cancel_at, "other.zzz"), -123);
/* more.zzz removed from index (so Index Adds 4 -> 3) and
* Just other.zzz removed (so Worktree Dels 2 -> 1) */
check_status(g_repo, 3, 0, 0, 0, 1, 0, 1, 0);
git_index_free(index);
}
void test_index_addall__adds_conflicts(void)
{
git_index *index;
git_reference *ref;
git_annotated_commit *annotated;
g_repo = cl_git_sandbox_init("merge-resolve");
cl_git_pass(git_repository_index(&index, g_repo));
check_status(g_repo, 0, 0, 0, 0, 0, 0, 0, 0);
cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/branch"));
cl_git_pass(git_annotated_commit_from_ref(&annotated, g_repo, ref));
cl_git_pass(git_merge(g_repo, (const git_annotated_commit**)&annotated, 1, NULL, NULL));
check_status(g_repo, 0, 1, 2, 0, 0, 0, 0, 1);
cl_git_pass(git_index_add_all(index, NULL, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_status(g_repo, 0, 1, 3, 0, 0, 0, 0, 0);
git_annotated_commit_free(annotated);
git_reference_free(ref);
git_index_free(index);
}
void test_index_addall__removes_deleted_conflicted_files(void)
{
git_index *index;
git_reference *ref;
git_annotated_commit *annotated;
g_repo = cl_git_sandbox_init("merge-resolve");
cl_git_pass(git_repository_index(&index, g_repo));
check_status(g_repo, 0, 0, 0, 0, 0, 0, 0, 0);
cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/branch"));
cl_git_pass(git_annotated_commit_from_ref(&annotated, g_repo, ref));
cl_git_pass(git_merge(g_repo, (const git_annotated_commit**)&annotated, 1, NULL, NULL));
check_status(g_repo, 0, 1, 2, 0, 0, 0, 0, 1);
cl_git_rmfile("merge-resolve/conflicting.txt");
cl_git_pass(git_index_add_all(index, NULL, 0, NULL, NULL));
cl_git_pass(git_index_write(index));
check_status(g_repo, 0, 2, 2, 0, 0, 0, 0, 0);
git_annotated_commit_free(annotated);
git_reference_free(ref);
git_index_free(index);
}
+362
View File
@@ -0,0 +1,362 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "../submodule/submodule_helpers.h"
static git_repository *g_repo;
static git_index *g_idx;
void test_index_bypath__initialize(void)
{
g_repo = setup_fixture_submod2();
cl_git_pass(git_repository_index__weakptr(&g_idx, g_repo));
}
void test_index_bypath__cleanup(void)
{
g_repo = NULL;
g_idx = NULL;
}
void test_index_bypath__add_directory(void)
{
cl_git_fail_with(GIT_EDIRECTORY, git_index_add_bypath(g_idx, "just_a_dir"));
}
void test_index_bypath__add_submodule(void)
{
unsigned int status;
const char *sm_name = "sm_changed_head";
cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0));
cl_assert_equal_i(GIT_SUBMODULE_STATUS_WD_MODIFIED, status & GIT_SUBMODULE_STATUS_WD_MODIFIED);
cl_git_pass(git_index_add_bypath(g_idx, sm_name));
cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0));
cl_assert_equal_i(0, status & GIT_SUBMODULE_STATUS_WD_MODIFIED);
}
void test_index_bypath__add_submodule_unregistered(void)
{
const char *sm_name = "not-submodule";
const char *sm_head = "68e92c611b80ee1ed8f38314ff9577f0d15b2444";
const git_index_entry *entry;
cl_git_pass(git_index_add_bypath(g_idx, sm_name));
cl_assert(entry = git_index_get_bypath(g_idx, sm_name, 0));
cl_assert_equal_s(sm_head, git_oid_tostr_s(&entry->id));
cl_assert_equal_s(sm_name, entry->path);
}
void test_index_bypath__add_hidden(void)
{
const git_index_entry *entry;
bool hidden;
GIT_UNUSED(entry);
GIT_UNUSED(hidden);
#ifdef GIT_WIN32
cl_git_mkfile("submod2/hidden_file", "you can't see me");
cl_git_pass(git_win32__hidden(&hidden, "submod2/hidden_file"));
cl_assert(!hidden);
cl_git_pass(git_win32__set_hidden("submod2/hidden_file", true));
cl_git_pass(git_win32__hidden(&hidden, "submod2/hidden_file"));
cl_assert(hidden);
cl_git_pass(git_index_add_bypath(g_idx, "hidden_file"));
cl_assert(entry = git_index_get_bypath(g_idx, "hidden_file", 0));
cl_assert_equal_i(GIT_FILEMODE_BLOB, entry->mode);
#endif
}
void test_index_bypath__add_keeps_existing_case(void)
{
const git_index_entry *entry;
if (!cl_repo_get_bool(g_repo, "core.ignorecase"))
clar__skip();
cl_git_mkfile("submod2/just_a_dir/file1.txt", "This is a file");
cl_git_pass(git_index_add_bypath(g_idx, "just_a_dir/file1.txt"));
cl_assert(entry = git_index_get_bypath(g_idx, "just_a_dir/file1.txt", 0));
cl_assert_equal_s("just_a_dir/file1.txt", entry->path);
cl_git_rewritefile("submod2/just_a_dir/file1.txt", "Updated!");
cl_git_pass(git_index_add_bypath(g_idx, "just_a_dir/FILE1.txt"));
cl_assert(entry = git_index_get_bypath(g_idx, "just_a_dir/FILE1.txt", 0));
cl_assert_equal_s("just_a_dir/file1.txt", entry->path);
}
void test_index_bypath__add_honors_existing_case(void)
{
const git_index_entry *entry;
if (!cl_repo_get_bool(g_repo, "core.ignorecase"))
clar__skip();
cl_git_mkfile("submod2/just_a_dir/file1.txt", "This is a file");
cl_git_mkfile("submod2/just_a_dir/file2.txt", "This is another file");
cl_git_mkfile("submod2/just_a_dir/file3.txt", "This is another file");
cl_git_mkfile("submod2/just_a_dir/file4.txt", "And another file");
cl_git_pass(git_index_add_bypath(g_idx, "just_a_dir/File1.txt"));
cl_git_pass(git_index_add_bypath(g_idx, "JUST_A_DIR/file2.txt"));
cl_git_pass(git_index_add_bypath(g_idx, "Just_A_Dir/FILE3.txt"));
cl_assert(entry = git_index_get_bypath(g_idx, "just_a_dir/File1.txt", 0));
cl_assert_equal_s("just_a_dir/File1.txt", entry->path);
cl_assert(entry = git_index_get_bypath(g_idx, "JUST_A_DIR/file2.txt", 0));
cl_assert_equal_s("just_a_dir/file2.txt", entry->path);
cl_assert(entry = git_index_get_bypath(g_idx, "Just_A_Dir/FILE3.txt", 0));
cl_assert_equal_s("just_a_dir/FILE3.txt", entry->path);
cl_git_rewritefile("submod2/just_a_dir/file3.txt", "Rewritten");
cl_git_pass(git_index_add_bypath(g_idx, "Just_A_Dir/file3.txt"));
cl_assert(entry = git_index_get_bypath(g_idx, "Just_A_Dir/file3.txt", 0));
cl_assert_equal_s("just_a_dir/FILE3.txt", entry->path);
}
void test_index_bypath__add_honors_existing_case_2(void)
{
git_index_entry dummy = { { 0 } };
const git_index_entry *entry;
if (!cl_repo_get_bool(g_repo, "core.ignorecase"))
clar__skip();
dummy.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_oid_fromstr(&dummy.id, "f990a25a74d1a8281ce2ab018ea8df66795cd60b"));
/* note that `git_index_add` does no checking to canonical directories */
dummy.path = "Just_a_dir/file0.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
dummy.path = "just_a_dir/fileA.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
dummy.path = "Just_A_Dir/fileB.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
dummy.path = "JUST_A_DIR/fileC.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
dummy.path = "just_A_dir/fileD.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
dummy.path = "JUST_a_DIR/fileE.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
cl_git_mkfile("submod2/just_a_dir/file1.txt", "This is a file");
cl_git_mkfile("submod2/just_a_dir/file2.txt", "This is another file");
cl_git_mkfile("submod2/just_a_dir/file3.txt", "This is another file");
cl_git_mkfile("submod2/just_a_dir/file4.txt", "And another file");
cl_git_pass(git_index_add_bypath(g_idx, "just_a_dir/File1.txt"));
cl_git_pass(git_index_add_bypath(g_idx, "JUST_A_DIR/file2.txt"));
cl_git_pass(git_index_add_bypath(g_idx, "Just_A_Dir/FILE3.txt"));
cl_git_pass(git_index_add_bypath(g_idx, "JusT_A_DIR/FILE4.txt"));
cl_assert(entry = git_index_get_bypath(g_idx, "just_a_dir/File1.txt", 0));
cl_assert_equal_s("just_a_dir/File1.txt", entry->path);
cl_assert(entry = git_index_get_bypath(g_idx, "JUST_A_DIR/file2.txt", 0));
cl_assert_equal_s("JUST_A_DIR/file2.txt", entry->path);
cl_assert(entry = git_index_get_bypath(g_idx, "Just_A_Dir/FILE3.txt", 0));
cl_assert_equal_s("Just_A_Dir/FILE3.txt", entry->path);
cl_git_rewritefile("submod2/just_a_dir/file3.txt", "Rewritten");
cl_git_pass(git_index_add_bypath(g_idx, "Just_A_Dir/file3.txt"));
cl_assert(entry = git_index_get_bypath(g_idx, "Just_A_Dir/file3.txt", 0));
cl_assert_equal_s("Just_A_Dir/FILE3.txt", entry->path);
}
void test_index_bypath__add_honors_existing_case_3(void)
{
git_index_entry dummy = { { 0 } };
const git_index_entry *entry;
if (!cl_repo_get_bool(g_repo, "core.ignorecase"))
clar__skip();
dummy.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_oid_fromstr(&dummy.id, "f990a25a74d1a8281ce2ab018ea8df66795cd60b"));
dummy.path = "just_a_dir/filea.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
dummy.path = "Just_A_Dir/fileB.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
dummy.path = "just_A_DIR/FILEC.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
dummy.path = "Just_a_DIR/FileD.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
cl_git_mkfile("submod2/JuSt_A_DiR/fILEE.txt", "This is a file");
cl_git_pass(git_index_add_bypath(g_idx, "just_a_dir/fILEE.txt"));
cl_assert(entry = git_index_get_bypath(g_idx, "JUST_A_DIR/fILEE.txt", 0));
cl_assert_equal_s("just_a_dir/fILEE.txt", entry->path);
}
void test_index_bypath__add_honors_existing_case_4(void)
{
git_index_entry dummy = { { 0 } };
const git_index_entry *entry;
if (!cl_repo_get_bool(g_repo, "core.ignorecase"))
clar__skip();
dummy.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_oid_fromstr(&dummy.id, "f990a25a74d1a8281ce2ab018ea8df66795cd60b"));
dummy.path = "just_a_dir/a/b/c/d/e/file1.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
dummy.path = "just_a_dir/a/B/C/D/E/file2.txt";
cl_git_pass(git_index_add(g_idx, &dummy));
cl_must_pass(p_mkdir("submod2/just_a_dir/a", 0777));
cl_must_pass(p_mkdir("submod2/just_a_dir/a/b", 0777));
cl_must_pass(p_mkdir("submod2/just_a_dir/a/b/z", 0777));
cl_must_pass(p_mkdir("submod2/just_a_dir/a/b/z/y", 0777));
cl_must_pass(p_mkdir("submod2/just_a_dir/a/b/z/y/x", 0777));
cl_git_mkfile("submod2/just_a_dir/a/b/z/y/x/FOO.txt", "This is a file");
cl_git_pass(git_index_add_bypath(g_idx, "just_a_dir/A/b/Z/y/X/foo.txt"));
cl_assert(entry = git_index_get_bypath(g_idx, "just_a_dir/A/b/Z/y/X/foo.txt", 0));
cl_assert_equal_s("just_a_dir/a/b/Z/y/X/foo.txt", entry->path);
}
void test_index_bypath__add_honors_mode(void)
{
const git_index_entry *entry;
git_index_entry new_entry;
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
memcpy(&new_entry, entry, sizeof(git_index_entry));
new_entry.path = "README.txt";
new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
cl_must_pass(p_chmod("submod2/README.txt", GIT_FILEMODE_BLOB_EXECUTABLE));
cl_git_pass(git_index_add(g_idx, &new_entry));
cl_git_pass(git_index_write(g_idx));
cl_git_rewritefile("submod2/README.txt", "Modified but still executable");
cl_git_pass(git_index_add_bypath(g_idx, "README.txt"));
cl_git_pass(git_index_write(g_idx));
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, entry->mode);
}
void test_index_bypath__add_honors_conflict_mode(void)
{
const git_index_entry *entry;
git_index_entry new_entry;
int stage = 0;
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
memcpy(&new_entry, entry, sizeof(git_index_entry));
new_entry.path = "README.txt";
new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
cl_must_pass(p_chmod("submod2/README.txt", GIT_FILEMODE_BLOB_EXECUTABLE));
cl_git_pass(git_index_remove_bypath(g_idx, "README.txt"));
for (stage = 1; stage <= 3; stage++) {
new_entry.flags = stage << GIT_INDEX_ENTRY_STAGESHIFT;
cl_git_pass(git_index_add(g_idx, &new_entry));
}
cl_git_pass(git_index_write(g_idx));
cl_git_rewritefile("submod2/README.txt", "Modified but still executable");
cl_git_pass(git_index_add_bypath(g_idx, "README.txt"));
cl_git_pass(git_index_write(g_idx));
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, entry->mode);
}
void test_index_bypath__add_honors_conflict_case(void)
{
const git_index_entry *entry;
git_index_entry new_entry;
int stage = 0;
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
memcpy(&new_entry, entry, sizeof(git_index_entry));
new_entry.path = "README.txt";
new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
cl_must_pass(p_chmod("submod2/README.txt", GIT_FILEMODE_BLOB_EXECUTABLE));
cl_git_pass(git_index_remove_bypath(g_idx, "README.txt"));
for (stage = 1; stage <= 3; stage++) {
new_entry.flags = stage << GIT_INDEX_ENTRY_STAGESHIFT;
cl_git_pass(git_index_add(g_idx, &new_entry));
}
cl_git_pass(git_index_write(g_idx));
cl_git_rewritefile("submod2/README.txt", "Modified but still executable");
cl_git_pass(git_index_add_bypath(g_idx, "README.txt"));
cl_git_pass(git_index_write(g_idx));
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, entry->mode);
}
void test_index_bypath__add_honors_symlink(void)
{
const git_index_entry *entry;
git_index_entry new_entry;
int symlinks;
cl_git_pass(git_repository__configmap_lookup(&symlinks, g_repo, GIT_CONFIGMAP_SYMLINKS));
if (symlinks)
cl_skip();
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
memcpy(&new_entry, entry, sizeof(git_index_entry));
new_entry.path = "README.txt";
new_entry.mode = GIT_FILEMODE_LINK;
cl_git_pass(git_index_add(g_idx, &new_entry));
cl_git_pass(git_index_write(g_idx));
cl_git_rewritefile("submod2/README.txt", "Modified but still a (fake) symlink");
cl_git_pass(git_index_add_bypath(g_idx, "README.txt"));
cl_git_pass(git_index_write(g_idx));
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
cl_assert_equal_i(GIT_FILEMODE_LINK, entry->mode);
}
+238
View File
@@ -0,0 +1,238 @@
#include "clar_libgit2.h"
#include "git2.h"
#include "index.h"
#include "tree-cache.h"
static git_repository *g_repo;
void test_index_cache__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_index_cache__cleanup(void)
{
cl_git_sandbox_cleanup();
g_repo = NULL;
}
void test_index_cache__write_extension_at_root(void)
{
git_index *index;
git_tree *tree;
git_oid id;
const char *tree_id_str = "45dd856fdd4d89b884c340ba0e047752d9b085d6";
const char *index_file = "index-tree";
cl_git_pass(git_index_open(&index, index_file));
cl_assert(index->tree == NULL);
cl_git_pass(git_oid_fromstr(&id, tree_id_str));
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
cl_git_pass(git_index_read_tree(index, tree));
git_tree_free(tree);
cl_assert(index->tree);
cl_git_pass(git_index_write(index));
git_index_free(index);
cl_git_pass(git_index_open(&index, index_file));
cl_assert(index->tree);
cl_assert_equal_i(git_index_entrycount(index), index->tree->entry_count);
cl_assert_equal_i(0, index->tree->children_count);
cl_assert(git_oid_equal(&id, &index->tree->oid));
cl_git_pass(p_unlink(index_file));
git_index_free(index);
}
void test_index_cache__write_extension_invalidated_root(void)
{
git_index *index;
git_tree *tree;
git_oid id;
const char *tree_id_str = "45dd856fdd4d89b884c340ba0e047752d9b085d6";
const char *index_file = "index-tree-invalidated";
git_index_entry entry;
cl_git_pass(git_index_open(&index, index_file));
cl_assert(index->tree == NULL);
cl_git_pass(git_oid_fromstr(&id, tree_id_str));
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
cl_git_pass(git_index_read_tree(index, tree));
git_tree_free(tree);
cl_assert(index->tree);
memset(&entry, 0x0, sizeof(git_index_entry));
git_oid_cpy(&entry.id, &git_index_get_byindex(index, 0)->id);
entry.mode = GIT_FILEMODE_BLOB;
entry.path = "some-new-file.txt";
cl_git_pass(git_index_add(index, &entry));
cl_assert_equal_i(-1, index->tree->entry_count);
cl_git_pass(git_index_write(index));
git_index_free(index);
cl_git_pass(git_index_open(&index, index_file));
cl_assert(index->tree);
cl_assert_equal_i(-1, index->tree->entry_count);
cl_assert_equal_i(0, index->tree->children_count);
cl_assert(git_oid_cmp(&id, &index->tree->oid));
cl_git_pass(p_unlink(index_file));
git_index_free(index);
}
void test_index_cache__read_tree_no_children(void)
{
git_index *index;
git_index_entry entry;
git_tree *tree;
git_oid id;
cl_git_pass(git_index_new(&index));
cl_assert(index->tree == NULL);
cl_git_pass(git_oid_fromstr(&id, "45dd856fdd4d89b884c340ba0e047752d9b085d6"));
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
cl_git_pass(git_index_read_tree(index, tree));
git_tree_free(tree);
cl_assert(index->tree);
cl_assert(git_oid_equal(&id, &index->tree->oid));
cl_assert_equal_i(0, index->tree->children_count);
cl_assert_equal_i(git_index_entrycount(index), index->tree->entry_count);
memset(&entry, 0x0, sizeof(git_index_entry));
entry.path = "new.txt";
entry.mode = GIT_FILEMODE_BLOB;
git_oid_fromstr(&entry.id, "d4bcc68acd4410bf836a39f20afb2c2ece09584e");
cl_git_pass(git_index_add(index, &entry));
cl_assert_equal_i(-1, index->tree->entry_count);
git_index_free(index);
}
void test_index_cache__two_levels(void)
{
git_tree *tree;
git_oid tree_id;
git_index *index;
git_index_entry entry;
const git_tree_cache *tree_cache;
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_clear(index));
memset(&entry, 0x0, sizeof(entry));
entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_oid_fromstr(&entry.id, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
entry.path = "top-level.txt";
cl_git_pass(git_index_add(index, &entry));
entry.path = "subdir/file.txt";
cl_git_pass(git_index_add(index, &entry));
/* the read-tree fills the tree cache */
cl_git_pass(git_index_write_tree(&tree_id, index));
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
cl_git_pass(git_index_read_tree(index, tree));
git_tree_free(tree);
cl_git_pass(git_index_write(index));
/* we now must have cache entries for "" and "subdir" */
cl_assert(index->tree);
cl_assert(git_tree_cache_get(index->tree, "subdir"));
cl_git_pass(git_index_read(index, true));
/* we must still have cache entries for "" and "subdir", since we wrote it out */
cl_assert(index->tree);
cl_assert(git_tree_cache_get(index->tree, "subdir"));
entry.path = "top-level.txt";
cl_git_pass(git_oid_fromstr(&entry.id, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc"));
cl_git_pass(git_index_add(index, &entry));
/* writ out the index after we invalidate the root */
cl_git_pass(git_index_write(index));
cl_git_pass(git_index_read(index, true));
/* the cache for the subtree must still be valid, even if the root isn't */
cl_assert(index->tree);
cl_assert_equal_i(-1, index->tree->entry_count);
cl_assert_equal_i(1, index->tree->children_count);
tree_cache = git_tree_cache_get(index->tree, "subdir");
cl_assert(tree_cache);
cl_assert_equal_i(1, tree_cache->entry_count);
git_index_free(index);
}
void test_index_cache__read_tree_children(void)
{
git_index *index;
git_index_entry entry;
git_tree *tree;
const git_tree_cache *cache;
git_oid tree_id;
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_clear(index));
cl_assert(index->tree == NULL);
/* add a bunch of entries at different levels */
memset(&entry, 0x0, sizeof(git_index_entry));
entry.path = "top-level";
entry.mode = GIT_FILEMODE_BLOB;
git_oid_fromstr(&entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
cl_git_pass(git_index_add(index, &entry));
entry.path = "subdir/some-file";
cl_git_pass(git_index_add(index, &entry));
entry.path = "subdir/even-deeper/some-file";
cl_git_pass(git_index_add(index, &entry));
entry.path = "subdir2/some-file";
cl_git_pass(git_index_add(index, &entry));
cl_git_pass(git_index_write_tree(&tree_id, index));
cl_git_pass(git_index_clear(index));
cl_assert(index->tree == NULL);
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
cl_git_pass(git_index_read_tree(index, tree));
git_tree_free(tree);
cl_assert(index->tree);
cl_assert_equal_i(2, index->tree->children_count);
/* override with a slightly different id, also dummy */
entry.path = "subdir/some-file";
git_oid_fromstr(&entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
cl_git_pass(git_index_add(index, &entry));
cl_assert_equal_i(-1, index->tree->entry_count);
cache = git_tree_cache_get(index->tree, "subdir");
cl_assert(cache);
cl_assert_equal_i(-1, cache->entry_count);
cache = git_tree_cache_get(index->tree, "subdir/even-deeper");
cl_assert(cache);
cl_assert_equal_i(1, cache->entry_count);
cache = git_tree_cache_get(index->tree, "subdir2");
cl_assert(cache);
cl_assert_equal_i(1, cache->entry_count);
git_index_free(index);
}
+149
View File
@@ -0,0 +1,149 @@
#include "clar_libgit2.h"
#include "git2/repository.h"
#include "git2/index.h"
static git_repository *g_repo;
static git_odb *g_odb;
static git_index *g_index;
static git_oid g_empty_id;
void test_index_collision__initialize(void)
{
g_repo = cl_git_sandbox_init("empty_standard_repo");
cl_git_pass(git_repository_odb(&g_odb, g_repo));
cl_git_pass(git_repository_index(&g_index, g_repo));
cl_git_pass(git_odb_write(&g_empty_id, g_odb, "", 0, GIT_OBJECT_BLOB));
}
void test_index_collision__cleanup(void)
{
git_index_free(g_index);
git_odb_free(g_odb);
cl_git_sandbox_cleanup();
}
void test_index_collision__add_blob_with_conflicting_file(void)
{
git_index_entry entry;
git_tree_entry *tentry;
git_oid tree_id;
git_tree *tree;
memset(&entry, 0, sizeof(entry));
entry.ctime.seconds = 12346789;
entry.mtime.seconds = 12346789;
entry.mode = 0100644;
entry.file_size = 0;
git_oid_cpy(&entry.id, &g_empty_id);
entry.path = "a/b";
cl_git_pass(git_index_add(g_index, &entry));
/* Check a/b exists here */
cl_git_pass(git_index_write_tree(&tree_id, g_index));
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
cl_git_pass(git_tree_entry_bypath(&tentry, tree, "a/b"));
git_tree_entry_free(tentry);
git_tree_free(tree);
/* create a tree/blob collision */
entry.path = "a/b/c";
cl_git_pass(git_index_add(g_index, &entry));
/* a/b should now be a tree and a/b/c a blob */
cl_git_pass(git_index_write_tree(&tree_id, g_index));
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
cl_git_pass(git_tree_entry_bypath(&tentry, tree, "a/b/c"));
git_tree_entry_free(tentry);
git_tree_free(tree);
}
void test_index_collision__add_blob_with_conflicting_dir(void)
{
git_index_entry entry;
git_tree_entry *tentry;
git_oid tree_id;
git_tree *tree;
memset(&entry, 0, sizeof(entry));
entry.ctime.seconds = 12346789;
entry.mtime.seconds = 12346789;
entry.mode = 0100644;
entry.file_size = 0;
git_oid_cpy(&entry.id, &g_empty_id);
entry.path = "a/b/c";
cl_git_pass(git_index_add(g_index, &entry));
/* Check a/b/c exists here */
cl_git_pass(git_index_write_tree(&tree_id, g_index));
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
cl_git_pass(git_tree_entry_bypath(&tentry, tree, "a/b/c"));
git_tree_entry_free(tentry);
git_tree_free(tree);
/* create a blob/tree collision */
entry.path = "a/b";
cl_git_pass(git_index_add(g_index, &entry));
/* a/b should now be a tree and a/b/c a blob */
cl_git_pass(git_index_write_tree(&tree_id, g_index));
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
cl_git_pass(git_tree_entry_bypath(&tentry, tree, "a/b"));
cl_git_fail(git_tree_entry_bypath(&tentry, tree, "a/b/c"));
git_tree_entry_free(tentry);
git_tree_free(tree);
}
void test_index_collision__add_with_highstage_1(void)
{
git_index_entry entry;
memset(&entry, 0, sizeof(entry));
entry.ctime.seconds = 12346789;
entry.mtime.seconds = 12346789;
entry.mode = 0100644;
entry.file_size = 0;
git_oid_cpy(&entry.id, &g_empty_id);
entry.path = "a/b";
GIT_INDEX_ENTRY_STAGE_SET(&entry, 2);
cl_git_pass(git_index_add(g_index, &entry));
/* create a blob beneath the previous tree entry */
entry.path = "a/b/c";
entry.flags = 0;
cl_git_pass(git_index_add(g_index, &entry));
/* create another tree entry above the blob */
entry.path = "a/b";
GIT_INDEX_ENTRY_STAGE_SET(&entry, 1);
cl_git_pass(git_index_add(g_index, &entry));
}
void test_index_collision__add_with_highstage_2(void)
{
git_index_entry entry;
memset(&entry, 0, sizeof(entry));
entry.ctime.seconds = 12346789;
entry.mtime.seconds = 12346789;
entry.mode = 0100644;
entry.file_size = 0;
git_oid_cpy(&entry.id, &g_empty_id);
entry.path = "a/b/c";
GIT_INDEX_ENTRY_STAGE_SET(&entry, 1);
cl_git_pass(git_index_add(g_index, &entry));
/* create a blob beneath the previous tree entry */
entry.path = "a/b/c";
GIT_INDEX_ENTRY_STAGE_SET(&entry, 2);
cl_git_pass(git_index_add(g_index, &entry));
/* create another tree entry above the blob */
entry.path = "a/b";
GIT_INDEX_ENTRY_STAGE_SET(&entry, 3);
cl_git_pass(git_index_add(g_index, &entry));
}
+462
View File
@@ -0,0 +1,462 @@
#include "clar_libgit2.h"
#include "index.h"
#include "git2/repository.h"
#include "conflicts.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_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.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 1);
git_oid_fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID);
our_entry.path = "test-one.txt";
our_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 2);
git_oid_fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID);
their_entry.path = "test-one.txt";
their_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 2);
git_oid_fromstr(&their_entry.id, CONFLICTS_ONE_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.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 3);
git_oid_fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID);
our_entry.path = "test-one.txt";
our_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 1);
git_oid_fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID);
their_entry.path = "test-one.txt";
their_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&their_entry, 2);
git_oid_fromstr(&their_entry.id, CONFLICTS_ONE_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__add_detects_invalid_filemode(void)
{
git_index_entry ancestor_entry, our_entry, their_entry;
git_index_entry *conflict_entry[3];
int i;
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));
conflict_entry[0] = &ancestor_entry;
conflict_entry[1] = &our_entry;
conflict_entry[2] = &their_entry;
for (i = 0; i < 3; i++) {
ancestor_entry.path = "test-one.txt";
ancestor_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 3);
git_oid_fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID);
our_entry.path = "test-one.txt";
our_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 1);
git_oid_fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID);
their_entry.path = "test-one.txt";
their_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&their_entry, 2);
git_oid_fromstr(&their_entry.id, CONFLICTS_ONE_THEIR_OID);
/* Corrupt the conflict entry's mode */
conflict_entry[i]->mode = 027431745;
cl_git_fail(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry));
}
cl_assert(git_index_entrycount(repo_index) == 8);
}
void test_index_conflicts__add_removes_stage_zero(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));
cl_git_mkfile("./mergedrepo/test-one.txt", "new-file\n");
cl_git_pass(git_index_add_bypath(repo_index, "test-one.txt"));
cl_assert(git_index_entrycount(repo_index) == 9);
ancestor_entry.path = "test-one.txt";
ancestor_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 3);
git_oid_fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID);
our_entry.path = "test-one.txt";
our_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 1);
git_oid_fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID);
their_entry.path = "test-one.txt";
their_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&their_entry, 2);
git_oid_fromstr(&their_entry.id, CONFLICTS_ONE_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_assert_equal_p(NULL, git_index_get_bypath(repo_index, "test-one.txt", 0));
cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], repo_index, "test-one.txt"));
cl_assert_equal_oid(&ancestor_entry.id, &conflict_entry[0]->id);
cl_assert_equal_i(1, git_index_entry_stage(conflict_entry[0]));
cl_assert_equal_oid(&our_entry.id, &conflict_entry[1]->id);
cl_assert_equal_i(2, git_index_entry_stage(conflict_entry[1]));
cl_assert_equal_oid(&their_entry.id, &conflict_entry[2]->id);
cl_assert_equal_i(3, git_index_entry_stage(conflict_entry[2]));
}
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_equal_oid(&oid, &conflict_entry[0]->id);
git_oid_fromstr(&oid, CONFLICTS_ONE_OUR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[1]->id);
git_oid_fromstr(&oid, CONFLICTS_ONE_THEIR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[2]->id);
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_equal_oid(&oid, &conflict_entry[0]->id);
git_oid_fromstr(&oid, CONFLICTS_TWO_OUR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[1]->id);
git_oid_fromstr(&oid, CONFLICTS_TWO_THEIR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[2]->id);
}
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_equal_oid(&oid, &conflict_entry[0]->id);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_ONE_OUR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[1]->id);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_ONE_THEIR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[2]->id);
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_equal_oid(&oid, &conflict_entry[0]->id);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_TWO_OUR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[1]->id);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_TWO_THEIR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[2]->id);
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_is_conflict(entry));
}
}
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_is_conflict(entry));
}
}
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.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 1);
git_oid_fromstr(&ancestor_entry.id, CONFLICTS_ONE_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_equal_oid(&ancestor_entry.id, &conflict_entry[0]->id);
cl_assert(conflict_entry[1] == NULL);
cl_assert(conflict_entry[2] == NULL);
}
void test_index_conflicts__case_matters(void)
{
const git_index_entry *conflict_entry[3];
git_oid oid;
const char *upper_case = "DIFFERS-IN-CASE.TXT";
const char *mixed_case = "Differs-In-Case.txt";
const char *correct_case;
bool ignorecase = cl_repo_get_bool(repo, "core.ignorecase");
git_index_entry ancestor_entry, our_entry, their_entry;
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 = upper_case;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, GIT_INDEX_STAGE_ANCESTOR);
git_oid_fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID);
ancestor_entry.mode = GIT_FILEMODE_BLOB;
our_entry.path = upper_case;
GIT_INDEX_ENTRY_STAGE_SET(&our_entry, GIT_INDEX_STAGE_OURS);
git_oid_fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID);
our_entry.mode = GIT_FILEMODE_BLOB;
their_entry.path = upper_case;
GIT_INDEX_ENTRY_STAGE_SET(&their_entry, GIT_INDEX_STAGE_THEIRS);
git_oid_fromstr(&their_entry.id, CONFLICTS_ONE_THEIR_OID);
their_entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_index_conflict_add(repo_index,
&ancestor_entry, &our_entry, &their_entry));
ancestor_entry.path = mixed_case;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, GIT_INDEX_STAGE_ANCESTOR);
git_oid_fromstr(&ancestor_entry.id, CONFLICTS_TWO_ANCESTOR_OID);
ancestor_entry.mode = GIT_FILEMODE_BLOB;
our_entry.path = mixed_case;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, GIT_INDEX_STAGE_ANCESTOR);
git_oid_fromstr(&our_entry.id, CONFLICTS_TWO_OUR_OID);
ancestor_entry.mode = GIT_FILEMODE_BLOB;
their_entry.path = mixed_case;
GIT_INDEX_ENTRY_STAGE_SET(&their_entry, GIT_INDEX_STAGE_THEIRS);
git_oid_fromstr(&their_entry.id, CONFLICTS_TWO_THEIR_OID);
their_entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_index_conflict_add(repo_index,
&ancestor_entry, &our_entry, &their_entry));
cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1],
&conflict_entry[2], repo_index, upper_case));
/*
* We inserted with mixed case last, so on a case-insensitive
* fs we should get the mixed case.
*/
if (ignorecase)
correct_case = mixed_case;
else
correct_case = upper_case;
cl_assert_equal_s(correct_case, conflict_entry[0]->path);
git_oid_fromstr(&oid, ignorecase ? CONFLICTS_TWO_ANCESTOR_OID : CONFLICTS_ONE_ANCESTOR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[0]->id);
cl_assert_equal_s(correct_case, conflict_entry[1]->path);
git_oid_fromstr(&oid, ignorecase ? CONFLICTS_TWO_OUR_OID : CONFLICTS_ONE_OUR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[1]->id);
cl_assert_equal_s(correct_case, conflict_entry[2]->path);
git_oid_fromstr(&oid, ignorecase ? CONFLICTS_TWO_THEIR_OID : CONFLICTS_ONE_THEIR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[2]->id);
cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1],
&conflict_entry[2], repo_index, mixed_case));
cl_assert_equal_s(mixed_case, conflict_entry[0]->path);
git_oid_fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[0]->id);
cl_assert_equal_s(mixed_case, conflict_entry[1]->path);
git_oid_fromstr(&oid, CONFLICTS_TWO_OUR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[1]->id);
cl_assert_equal_s(mixed_case, conflict_entry[2]->path);
git_oid_fromstr(&oid, CONFLICTS_TWO_THEIR_OID);
cl_assert_equal_oid(&oid, &conflict_entry[2]->id);
}
+7
View File
@@ -0,0 +1,7 @@
#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"
+402
View File
@@ -0,0 +1,402 @@
#include "clar_libgit2.h"
#include "../filter/crlf.h"
#include "git2/checkout.h"
#include "repository.h"
#include "posix.h"
#define FILE_CONTENTS_LF "one\ntwo\nthree\nfour\n"
#define FILE_CONTENTS_CRLF "one\r\ntwo\r\nthree\r\nfour\r\n"
#define FILE_OID_LF "f384549cbeb481e437091320de6d1f2e15e11b4a"
#define FILE_OID_CRLF "7fbf4d847b191141d80f30c8ab03d2ad4cd543a9"
static git_repository *g_repo;
static git_index *g_index;
static git_buf expected_fixture = GIT_BUF_INIT;
void test_index_crlf__initialize(void)
{
g_repo = cl_git_sandbox_init_new("crlf");
cl_git_pass(git_repository_index(&g_index, g_repo));
}
void test_index_crlf__cleanup(void)
{
git_index_free(g_index);
cl_git_sandbox_cleanup();
if (expected_fixture.size) {
cl_fixture_cleanup(expected_fixture.ptr);
git_buf_dispose(&expected_fixture);
}
}
struct compare_data
{
const char *systype;
const char *dirname;
const char *safecrlf;
const char *autocrlf;
const char *attrs;
};
static int add_and_check_file(void *payload, git_buf *actual_path)
{
git_buf expected_path = GIT_BUF_INIT;
git_buf expected_path_fail = GIT_BUF_INIT;
git_buf expected_contents = GIT_BUF_INIT;
struct compare_data *cd = payload;
char *basename;
const git_index_entry *entry;
git_blob *blob;
bool failed = true;
basename = git_path_basename(actual_path->ptr);
if (!strcmp(basename, ".git") || !strcmp(basename, ".gitattributes")) {
failed = false;
goto done;
}
cl_git_pass(git_buf_joinpath(&expected_path, cd->dirname, basename));
cl_git_pass(git_buf_puts(&expected_path_fail, expected_path.ptr));
cl_git_pass(git_buf_puts(&expected_path_fail, ".fail"));
if (git_path_isfile(expected_path.ptr)) {
cl_git_pass(git_index_add_bypath(g_index, basename));
cl_assert(entry = git_index_get_bypath(g_index, basename, 0));
cl_git_pass(git_blob_lookup(&blob, g_repo, &entry->id));
cl_git_pass(git_futils_readbuffer(&expected_contents, expected_path.ptr));
if (strcmp(expected_contents.ptr, git_blob_rawcontent(blob)) != 0)
goto done;
git_blob_free(blob);
} else if (git_path_isfile(expected_path_fail.ptr)) {
cl_git_pass(git_futils_readbuffer(&expected_contents, expected_path_fail.ptr));
git_buf_rtrim(&expected_contents);
if (git_index_add_bypath(g_index, basename) == 0 ||
git_error_last()->klass != GIT_ERROR_FILTER ||
strcmp(expected_contents.ptr, git_error_last()->message) != 0)
goto done;
} else {
cl_fail("unexpected index failure");
}
failed = false;
done:
if (failed) {
git_buf details = GIT_BUF_INIT;
git_buf_printf(&details, "filename=%s, system=%s, autocrlf=%s, safecrlf=%s, attrs={%s}",
basename, cd->systype, cd->autocrlf, cd->safecrlf, cd->attrs);
clar__fail(__FILE__, __LINE__,
"index contents did not match expected", details.ptr, 0);
git_buf_dispose(&details);
}
git__free(basename);
git_buf_dispose(&expected_contents);
git_buf_dispose(&expected_path);
git_buf_dispose(&expected_path_fail);
return 0;
}
static const char *system_type(void)
{
if (GIT_EOL_NATIVE == GIT_EOL_CRLF)
return "windows";
else
return "posix";
}
static void test_add_index(const char *safecrlf, const char *autocrlf, const char *attrs)
{
git_buf attrbuf = GIT_BUF_INIT;
git_buf expected_dirname = GIT_BUF_INIT;
git_buf sandboxname = GIT_BUF_INIT;
git_buf reponame = GIT_BUF_INIT;
struct compare_data compare_data = { system_type(), NULL, safecrlf, autocrlf, attrs };
const char *c;
git_buf_puts(&reponame, "crlf");
git_buf_puts(&sandboxname, "autocrlf_");
git_buf_puts(&sandboxname, autocrlf);
git_buf_puts(&sandboxname, ",safecrlf_");
git_buf_puts(&sandboxname, safecrlf);
if (*attrs) {
git_buf_puts(&sandboxname, ",");
for (c = attrs; *c; c++) {
if (*c == ' ')
git_buf_putc(&sandboxname, ',');
else if (*c == '=')
git_buf_putc(&sandboxname, '_');
else
git_buf_putc(&sandboxname, *c);
}
git_buf_printf(&attrbuf, "* %s\n", attrs);
cl_git_mkfile("crlf/.gitattributes", attrbuf.ptr);
}
cl_repo_set_string(g_repo, "core.safecrlf", safecrlf);
cl_repo_set_string(g_repo, "core.autocrlf", autocrlf);
cl_git_pass(git_index_clear(g_index));
git_buf_joinpath(&expected_dirname, "crlf_data", system_type());
git_buf_puts(&expected_dirname, "_to_odb");
git_buf_joinpath(&expected_fixture, expected_dirname.ptr, sandboxname.ptr);
cl_fixture_sandbox(expected_fixture.ptr);
compare_data.dirname = sandboxname.ptr;
cl_git_pass(git_path_direach(&reponame, 0, add_and_check_file, &compare_data));
cl_fixture_cleanup(expected_fixture.ptr);
git_buf_dispose(&expected_fixture);
git_buf_dispose(&attrbuf);
git_buf_dispose(&expected_fixture);
git_buf_dispose(&expected_dirname);
git_buf_dispose(&sandboxname);
git_buf_dispose(&reponame);
}
static void set_up_workingdir(const char *name)
{
git_vector contents = GIT_VECTOR_INIT;
size_t i;
const char *fn;
git_path_dirload(&contents, name, 0, 0);
git_vector_foreach(&contents, i, fn) {
char *basename = git_path_basename(fn);
bool skip = strncasecmp(basename, ".git", 4) == 0 && strlen(basename) == 4;
git__free(basename);
if (skip)
continue;
p_unlink(fn);
}
git_vector_free_deep(&contents);
/* copy input files */
git_path_dirload(&contents, cl_fixture("crlf"), 0, 0);
git_vector_foreach(&contents, i, fn) {
char *basename = git_path_basename(fn);
git_buf dest_filename = GIT_BUF_INIT;
if (strcmp(basename, ".gitted") &&
strcmp(basename, ".gitattributes")) {
git_buf_joinpath(&dest_filename, name, basename);
cl_git_pass(git_futils_cp(fn, dest_filename.ptr, 0644));
}
git__free(basename);
git_buf_dispose(&dest_filename);
}
git_vector_free_deep(&contents);
}
void test_index_crlf__matches_core_git(void)
{
const char *safecrlf[] = { "true", "false", "warn", NULL };
const char *autocrlf[] = { "true", "false", "input", NULL };
const char *attrs[] = { "", "-crlf", "-text", "eol=crlf", "eol=lf",
"text", "text eol=crlf", "text eol=lf",
"text=auto", "text=auto eol=crlf", "text=auto eol=lf",
NULL };
const char **a, **b, **c;
for (a = safecrlf; *a; a++) {
for (b = autocrlf; *b; b++) {
for (c = attrs; *c; c++) {
set_up_workingdir("crlf");
test_add_index(*a, *b, *c);
}
}
}
}
void test_index_crlf__autocrlf_false_no_attrs(void)
{
const git_index_entry *entry;
git_oid oid;
cl_repo_set_bool(g_repo, "core.autocrlf", false);
cl_git_mkfile("./crlf/newfile.txt",
(GIT_EOL_NATIVE == GIT_EOL_CRLF) ? FILE_CONTENTS_CRLF : FILE_CONTENTS_LF);
cl_git_pass(git_index_add_bypath(g_index, "newfile.txt"));
entry = git_index_get_bypath(g_index, "newfile.txt", 0);
cl_git_pass(git_oid_fromstr(&oid,
(GIT_EOL_NATIVE == GIT_EOL_CRLF) ? FILE_OID_CRLF : FILE_OID_LF));
cl_assert_equal_oid(&oid, &entry->id);
}
void test_index_crlf__autocrlf_true_no_attrs(void)
{
const git_index_entry *entry;
git_oid oid;
cl_repo_set_bool(g_repo, "core.autocrlf", true);
cl_git_mkfile("./crlf/newfile.txt",
(GIT_EOL_NATIVE == GIT_EOL_CRLF) ? FILE_CONTENTS_CRLF : FILE_CONTENTS_LF);
cl_git_pass(git_index_add_bypath(g_index, "newfile.txt"));
entry = git_index_get_bypath(g_index, "newfile.txt", 0);
cl_git_pass(git_oid_fromstr(&oid, FILE_OID_LF));
cl_assert_equal_oid(&oid, &entry->id);
}
void test_index_crlf__autocrlf_input_no_attrs(void)
{
const git_index_entry *entry;
git_oid oid;
cl_repo_set_string(g_repo, "core.autocrlf", "input");
cl_git_mkfile("./crlf/newfile.txt",
(GIT_EOL_NATIVE == GIT_EOL_CRLF) ? FILE_CONTENTS_CRLF : FILE_CONTENTS_LF);
cl_git_pass(git_index_add_bypath(g_index, "newfile.txt"));
entry = git_index_get_bypath(g_index, "newfile.txt", 0);
cl_git_pass(git_oid_fromstr(&oid, FILE_OID_LF));
cl_assert_equal_oid(&oid, &entry->id);
}
void test_index_crlf__autocrlf_false_text_auto_attr(void)
{
const git_index_entry *entry;
git_oid oid;
cl_git_mkfile("./crlf/.gitattributes", "* text=auto\n");
cl_repo_set_bool(g_repo, "core.autocrlf", false);
cl_git_mkfile("./crlf/newfile.txt",
(GIT_EOL_NATIVE == GIT_EOL_CRLF) ? FILE_CONTENTS_CRLF : FILE_CONTENTS_LF);
cl_git_pass(git_index_add_bypath(g_index, "newfile.txt"));
entry = git_index_get_bypath(g_index, "newfile.txt", 0);
cl_git_pass(git_oid_fromstr(&oid, FILE_OID_LF));
cl_assert_equal_oid(&oid, &entry->id);
}
void test_index_crlf__autocrlf_true_text_auto_attr(void)
{
const git_index_entry *entry;
git_oid oid;
cl_git_mkfile("./crlf/.gitattributes", "* text=auto\n");
cl_repo_set_bool(g_repo, "core.autocrlf", false);
cl_git_mkfile("./crlf/newfile.txt",
(GIT_EOL_NATIVE == GIT_EOL_CRLF) ? FILE_CONTENTS_CRLF : FILE_CONTENTS_LF);
cl_git_pass(git_index_add_bypath(g_index, "newfile.txt"));
entry = git_index_get_bypath(g_index, "newfile.txt", 0);
cl_git_pass(git_oid_fromstr(&oid, FILE_OID_LF));
cl_assert_equal_oid(&oid, &entry->id);
}
void test_index_crlf__autocrlf_input_text_auto_attr(void)
{
const git_index_entry *entry;
git_oid oid;
cl_git_mkfile("./crlf/.gitattributes", "* text=auto\n");
cl_repo_set_string(g_repo, "core.autocrlf", "input");
cl_git_mkfile("./crlf/newfile.txt",
(GIT_EOL_NATIVE == GIT_EOL_CRLF) ? FILE_CONTENTS_CRLF : FILE_CONTENTS_LF);
cl_git_pass(git_index_add_bypath(g_index, "newfile.txt"));
entry = git_index_get_bypath(g_index, "newfile.txt", 0);
cl_git_pass(git_oid_fromstr(&oid, FILE_OID_LF));
cl_assert_equal_oid(&oid, &entry->id);
}
void test_index_crlf__safecrlf_true_autocrlf_input_text_auto_attr(void)
{
const git_index_entry *entry;
git_oid oid;
cl_git_mkfile("./crlf/.gitattributes", "* text=auto\n");
cl_repo_set_string(g_repo, "core.autocrlf", "input");
cl_repo_set_bool(g_repo, "core.safecrlf", true);
cl_git_mkfile("./crlf/newfile.txt", FILE_CONTENTS_LF);
cl_git_pass(git_index_add_bypath(g_index, "newfile.txt"));
entry = git_index_get_bypath(g_index, "newfile.txt", 0);
cl_assert(entry);
cl_git_pass(git_oid_fromstr(&oid, FILE_OID_LF));
cl_assert_equal_oid(&oid, &entry->id);
cl_git_mkfile("./crlf/newfile2.txt", FILE_CONTENTS_CRLF);
cl_git_fail(git_index_add_bypath(g_index, "newfile2.txt"));
}
void test_index_crlf__safecrlf_true_autocrlf_input_text__no_attr(void)
{
const git_index_entry *entry;
git_oid oid;
cl_repo_set_string(g_repo, "core.autocrlf", "input");
cl_repo_set_bool(g_repo, "core.safecrlf", true);
cl_git_mkfile("./crlf/newfile.txt", FILE_CONTENTS_LF);
cl_git_pass(git_index_add_bypath(g_index, "newfile.txt"));
entry = git_index_get_bypath(g_index, "newfile.txt", 0);
cl_assert(entry);
cl_git_pass(git_oid_fromstr(&oid, FILE_OID_LF));
cl_assert_equal_oid(&oid, &entry->id);
cl_git_mkfile("./crlf/newfile2.txt", FILE_CONTENTS_CRLF);
cl_git_fail(git_index_add_bypath(g_index, "newfile2.txt"));
}
void test_index_crlf__safecrlf_true_no_attrs(void)
{
cl_repo_set_bool(g_repo, "core.autocrlf", true);
cl_repo_set_bool(g_repo, "core.safecrlf", true);
cl_git_mkfile("crlf/newfile.txt", ALL_LF_TEXT_RAW);
cl_git_fail(git_index_add_bypath(g_index, "newfile.txt"));
cl_git_mkfile("crlf/newfile.txt", ALL_CRLF_TEXT_RAW);
cl_git_pass(git_index_add_bypath(g_index, "newfile.txt"));
cl_git_mkfile("crlf/newfile.txt", MORE_CRLF_TEXT_RAW);
cl_git_fail(git_index_add_bypath(g_index, "newfile.txt"));
cl_git_mkfile("crlf/newfile.txt", MORE_LF_TEXT_RAW);
cl_git_fail(git_index_add_bypath(g_index, "newfile.txt"));
}
+320
View File
@@ -0,0 +1,320 @@
#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_dispose(&path);
git_buf_dispose(&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_INDEX_CAPABILITY_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_INDEX_CAPABILITY_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);
}
#define add_entry_and_check_mode(I,FF,X) add_entry_and_check_mode_(I,FF,X,__FILE__,__LINE__)
static void add_entry_and_check_mode_(
git_index *index, bool from_file, git_filemode_t mode,
const char *file, int line)
{
size_t pos;
const git_index_entry* entry;
git_index_entry new_entry;
/* If old_filename exists, we copy that to the new file, and test
* git_index_add(), otherwise create a new entry testing git_index_add_from_buffer
*/
if (from_file)
{
clar__assert(!git_index_find(&pos, index, "exec_off"),
file, line, "Cannot find original index entry", NULL, 1);
entry = git_index_get_byindex(index, pos);
memcpy(&new_entry, entry, sizeof(new_entry));
}
else
memset(&new_entry, 0x0, sizeof(git_index_entry));
new_entry.path = "filemodes/explicit_test";
new_entry.mode = mode;
if (from_file)
{
clar__assert(!git_index_add(index, &new_entry),
file, line, "Cannot add index entry", NULL, 1);
}
else
{
const char *content = "hey there\n";
clar__assert(!git_index_add_from_buffer(index, &new_entry, content, strlen(content)),
file, line, "Cannot add index entry from buffer", NULL, 1);
}
clar__assert(!git_index_find(&pos, index, "filemodes/explicit_test"),
file, line, "Cannot find new 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)mode);
}
void test_index_filemodes__explicit(void)
{
git_index *index;
/* These tests should run and work everywhere, as the filemode is
* given explicitly to git_index_add or git_index_add_from_buffer
*/
cl_repo_set_bool(g_repo, "core.filemode", false);
cl_git_pass(git_repository_index(&index, g_repo));
/* Each of these tests keeps overwriting the same file in the index. */
/* 1 - add new 0644 entry */
add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB);
/* 2 - add 0755 entry over existing 0644 */
add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB_EXECUTABLE);
/* 3 - add 0644 entry over existing 0755 */
add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB);
/* 4 - add 0755 buffer entry over existing 0644 */
add_entry_and_check_mode(index, false, GIT_FILEMODE_BLOB_EXECUTABLE);
/* 5 - add 0644 buffer entry over existing 0755 */
add_entry_and_check_mode(index, false, GIT_FILEMODE_BLOB);
git_index_free(index);
}
void test_index_filemodes__invalid(void)
{
git_index *index;
git_index_entry entry;
const git_index_entry *dummy;
cl_git_pass(git_repository_index(&index, g_repo));
/* add a dummy file so that we have a valid id */
cl_git_mkfile("./filemodes/dummy-file.txt", "new-file\n");
cl_git_pass(git_index_add_bypath(index, "dummy-file.txt"));
cl_assert((dummy = git_index_get_bypath(index, "dummy-file.txt", 0)));
GIT_INDEX_ENTRY_STAGE_SET(&entry, 0);
entry.path = "foo";
entry.mode = GIT_OBJECT_BLOB;
git_oid_cpy(&entry.id, &dummy->id);
cl_git_fail(git_index_add(index, &entry));
entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_index_add(index, &entry));
git_index_free(index);
}
void test_index_filemodes__frombuffer_requires_files(void)
{
git_index *index;
git_index_entry new_entry;
const git_index_entry *ret_entry;
const char *content = "hey there\n";
memset(&new_entry, 0, sizeof(new_entry));
cl_git_pass(git_repository_index(&index, g_repo));
/* regular blob */
new_entry.path = "dummy-file.txt";
new_entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert((ret_entry = git_index_get_bypath(index, "dummy-file.txt", 0)));
cl_assert_equal_s("dummy-file.txt", ret_entry->path);
cl_assert_equal_i(GIT_FILEMODE_BLOB, ret_entry->mode);
/* executable blob */
new_entry.path = "dummy-file.txt";
new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
cl_git_pass(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert((ret_entry = git_index_get_bypath(index, "dummy-file.txt", 0)));
cl_assert_equal_s("dummy-file.txt", ret_entry->path);
cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, ret_entry->mode);
/* links are also acceptable */
new_entry.path = "dummy-link.txt";
new_entry.mode = GIT_FILEMODE_LINK;
cl_git_pass(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert((ret_entry = git_index_get_bypath(index, "dummy-link.txt", 0)));
cl_assert_equal_s("dummy-link.txt", ret_entry->path);
cl_assert_equal_i(GIT_FILEMODE_LINK, ret_entry->mode);
/* trees are rejected */
new_entry.path = "invalid_mode.txt";
new_entry.mode = GIT_FILEMODE_TREE;
cl_git_fail(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert_equal_p(NULL, git_index_get_bypath(index, "invalid_mode.txt", 0));
/* submodules are rejected */
new_entry.path = "invalid_mode.txt";
new_entry.mode = GIT_FILEMODE_COMMIT;
cl_git_fail(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert_equal_p(NULL, git_index_get_bypath(index, "invalid_mode.txt", 0));
git_index_free(index);
}
+22
View File
@@ -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);
}
+187
View File
@@ -0,0 +1,187 @@
#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();
}
static void index_add_conflicts(void)
{
git_index_entry entry = {{0}};
const char *paths[][3] = {
{ "ancestor", "ours", "theirs" },
{ "ancestor2", "ours2", "theirs2" },
{ "ancestor3", "ours3", "theirs3" } };
const char **conflict;
size_t i;
for (i = 0; i < ARRAY_SIZE(paths); i++) {
conflict = paths[i];
/* ancestor */
entry.path = conflict[0];
entry.mode = GIT_FILEMODE_BLOB;
GIT_INDEX_ENTRY_STAGE_SET(&entry, GIT_INDEX_STAGE_ANCESTOR);
git_oid_fromstr(&entry.id, "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81");
cl_git_pass(git_index_add(repo_index, &entry));
/* ours */
entry.path = conflict[1];
entry.mode = GIT_FILEMODE_BLOB;
GIT_INDEX_ENTRY_STAGE_SET(&entry, GIT_INDEX_STAGE_OURS);
git_oid_fromstr(&entry.id, "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81");
cl_git_pass(git_index_add(repo_index, &entry));
/* theirs */
entry.path = conflict[2];
entry.mode = GIT_FILEMODE_BLOB;
GIT_INDEX_ENTRY_STAGE_SET(&entry, GIT_INDEX_STAGE_THEIRS);
git_oid_fromstr(&entry.id, "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81");
cl_git_pass(git_index_add(repo_index, &entry));
}
}
void test_index_names__add(void)
{
const git_index_name_entry *conflict_name;
index_add_conflicts();
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);
cl_git_pass(git_index_write(repo_index));
}
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;
cl_git_pass(git_revparse_single(&target, repo, "3a34580"));
test_index_names__add();
cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL));
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;
cl_git_pass(git_revparse_single(&target, repo, "3a34580"));
test_index_names__add();
cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL));
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_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_UPDATE_ONLY;
test_index_names__add();
cl_git_pass(git_reference_name_to_id(&oid, repo, "refs/heads/master"));
cl_git_pass(git_object_lookup(&obj, repo, &oid, GIT_OBJECT_ANY));
cl_git_pass(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_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_UPDATE_ONLY;
test_index_names__add();
cl_git_pass(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_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_UPDATE_ONLY;
test_index_names__add();
cl_git_pass(git_checkout_index(repo, repo_index, &opts));
cl_assert(git_index_name_entrycount(repo_index) > 0);
}
+129
View File
@@ -0,0 +1,129 @@
#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 "nsecs"
/* Fixture setup and teardown */
void test_index_nsec__initialize(void)
{
repo = cl_git_sandbox_init("nsecs");
git_repository_index(&repo_index, repo);
}
void test_index_nsec__cleanup(void)
{
git_index_free(repo_index);
repo_index = NULL;
cl_git_sandbox_cleanup();
}
static bool try_create_file_with_nsec_timestamp(const char *path)
{
struct stat st;
int try;
/* retry a few times to avoid nanos *actually* equal 0 race condition */
for (try = 0; try < 3; try++) {
cl_git_mkfile(path, "This is hopefully a file with nanoseconds!");
cl_must_pass(p_stat(path, &st));
if (st.st_ctime_nsec && st.st_mtime_nsec)
return true;
}
return false;
}
/* try to determine if the underlying filesystem supports a resolution
* higher than a single second. (i'm looking at you, hfs+)
*/
static bool should_expect_nsecs(void)
{
git_buf nsec_path = GIT_BUF_INIT;
bool expect;
git_buf_joinpath(&nsec_path, clar_sandbox_path(), "nsec_test");
expect = try_create_file_with_nsec_timestamp(nsec_path.ptr);
p_unlink(nsec_path.ptr);
git_buf_dispose(&nsec_path);
return expect;
}
static bool has_nsecs(void)
{
const git_index_entry *entry;
size_t i;
bool has_nsecs = false;
for (i = 0; i < git_index_entrycount(repo_index); i++) {
entry = git_index_get_byindex(repo_index, i);
if (entry->ctime.nanoseconds || entry->mtime.nanoseconds) {
has_nsecs = true;
break;
}
}
return has_nsecs;
}
void test_index_nsec__has_nanos(void)
{
cl_assert_equal_b(true, has_nsecs());
}
void test_index_nsec__staging_maintains_other_nanos(void)
{
const git_index_entry *entry;
bool expect_nsec, test_file_has_nsec;
expect_nsec = should_expect_nsecs();
test_file_has_nsec = try_create_file_with_nsec_timestamp("nsecs/a.txt");
cl_assert_equal_b(expect_nsec, test_file_has_nsec);
cl_git_pass(git_index_add_bypath(repo_index, "a.txt"));
cl_git_pass(git_index_write(repo_index));
cl_git_pass(git_index_write(repo_index));
git_index_read(repo_index, 1);
cl_assert_equal_b(true, has_nsecs());
cl_assert((entry = git_index_get_bypath(repo_index, "a.txt", 0)));
/* if we are writing nanoseconds to the index, expect them to be
* nonzero.
*/
if (expect_nsec) {
cl_assert(entry->ctime.nanoseconds != 0);
cl_assert(entry->mtime.nanoseconds != 0);
} else {
cl_assert_equal_i(0, entry->ctime.nanoseconds);
cl_assert_equal_i(0, entry->mtime.nanoseconds);
}
}
void test_index_nsec__status_doesnt_clear_nsecs(void)
{
git_status_list *statuslist;
cl_git_pass(git_status_list_new(&statuslist, repo, NULL));
git_index_read(repo_index, 1);
cl_assert_equal_b(true, has_nsecs());
git_status_list_free(statuslist);
}
+324
View File
@@ -0,0 +1,324 @@
#include "clar_libgit2.h"
#include "../checkout/checkout_helpers.h"
#include "buffer.h"
#include "index.h"
#include "repository.h"
static git_repository *g_repo;
void test_index_racy__initialize(void)
{
cl_git_pass(git_repository_init(&g_repo, "diff_racy", false));
}
void test_index_racy__cleanup(void)
{
git_repository_free(g_repo);
g_repo = NULL;
cl_fixture_cleanup("diff_racy");
}
void test_index_racy__diff(void)
{
git_index *index;
git_diff *diff;
git_buf path = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "A"));
cl_git_mkfile(path.ptr, "A");
/* Put 'A' into the index */
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_add_bypath(index, "A"));
cl_git_pass(git_index_write(index));
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, index, NULL));
cl_assert_equal_i(0, git_diff_num_deltas(diff));
git_diff_free(diff);
/* Change its contents quickly, so we get the same timestamp */
cl_git_mkfile(path.ptr, "B");
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, index, NULL));
cl_assert_equal_i(1, git_diff_num_deltas(diff));
git_index_free(index);
git_diff_free(diff);
git_buf_dispose(&path);
}
void test_index_racy__write_index_just_after_file(void)
{
git_index *index;
git_diff *diff;
git_buf path = GIT_BUF_INIT;
struct p_timeval times[2];
/* Make sure we do have a timestamp */
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_write(index));
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "A"));
cl_git_mkfile(path.ptr, "A");
/* Force the file's timestamp to be a second after we wrote the index */
times[0].tv_sec = index->stamp.mtime.tv_sec + 1;
times[0].tv_usec = index->stamp.mtime.tv_nsec / 1000;
times[1].tv_sec = index->stamp.mtime.tv_sec + 1;
times[1].tv_usec = index->stamp.mtime.tv_nsec / 1000;
cl_git_pass(p_utimes(path.ptr, times));
/*
* Put 'A' into the index, the size field will be filled,
* because the index' on-disk timestamp does not match the
* file's timestamp.
*/
cl_git_pass(git_index_add_bypath(index, "A"));
cl_git_pass(git_index_write(index));
cl_git_mkfile(path.ptr, "B");
/*
* Pretend this index' modification happened a second after the
* file update, and rewrite the file in that same second.
*/
times[0].tv_sec = index->stamp.mtime.tv_sec + 2;
times[0].tv_usec = index->stamp.mtime.tv_nsec / 1000;
times[1].tv_sec = index->stamp.mtime.tv_sec + 2;
times[0].tv_usec = index->stamp.mtime.tv_nsec / 1000;
cl_git_pass(p_utimes(git_index_path(index), times));
cl_git_pass(p_utimes(path.ptr, times));
cl_git_pass(git_index_read(index, true));
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, index, NULL));
cl_assert_equal_i(1, git_diff_num_deltas(diff));
git_buf_dispose(&path);
git_diff_free(diff);
git_index_free(index);
}
static void setup_race(void)
{
git_buf path = GIT_BUF_INIT;
git_index *index;
git_index_entry *entry;
struct stat st;
/* Make sure we do have a timestamp */
cl_git_pass(git_repository_index__weakptr(&index, g_repo));
cl_git_pass(git_index_write(index));
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "A"));
cl_git_mkfile(path.ptr, "A");
cl_git_pass(git_index_add_bypath(index, "A"));
cl_git_mkfile(path.ptr, "B");
cl_git_pass(git_index_write(index));
cl_git_mkfile(path.ptr, "");
cl_git_pass(p_stat(path.ptr, &st));
cl_assert(entry = (git_index_entry *)git_index_get_bypath(index, "A", 0));
/* force a race */
entry->mtime.seconds = (int32_t)st.st_mtime;
entry->mtime.nanoseconds = (int32_t)st.st_mtime_nsec;
git_buf_dispose(&path);
}
void test_index_racy__smudges_index_entry_on_save(void)
{
git_index *index;
const git_index_entry *entry;
setup_race();
/* write the index, which will smudge anything that had the same timestamp
* as the index when the index was loaded. that way future loads of the
* index (with the new timestamp) will know that these files were not
* clean.
*/
cl_git_pass(git_repository_index__weakptr(&index, g_repo));
cl_git_pass(git_index_write(index));
cl_assert(entry = git_index_get_bypath(index, "A", 0));
cl_assert_equal_i(0, entry->file_size);
}
void test_index_racy__detects_diff_of_change_in_identical_timestamp(void)
{
git_index *index;
git_diff *diff;
cl_git_pass(git_repository_index__weakptr(&index, g_repo));
setup_race();
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, index, NULL));
cl_assert_equal_i(1, git_diff_num_deltas(diff));
git_diff_free(diff);
}
static void setup_uptodate_files(void)
{
git_buf path = GIT_BUF_INIT;
git_index *index;
const git_index_entry *a_entry;
git_index_entry new_entry = {{0}};
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "A"));
cl_git_mkfile(path.ptr, "A");
/* Put 'A' into the index */
cl_git_pass(git_index_add_bypath(index, "A"));
cl_assert((a_entry = git_index_get_bypath(index, "A", 0)));
/* Put 'B' into the index */
new_entry.path = "B";
new_entry.mode = GIT_FILEMODE_BLOB;
git_oid_cpy(&new_entry.id, &a_entry->id);
cl_git_pass(git_index_add(index, &new_entry));
/* Put 'C' into the index */
new_entry.path = "C";
new_entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_index_add_from_buffer(index, &new_entry, "hello!\n", 7));
git_index_free(index);
git_buf_dispose(&path);
}
void test_index_racy__adding_to_index_is_uptodate(void)
{
git_index *index;
const git_index_entry *entry;
setup_uptodate_files();
cl_git_pass(git_repository_index(&index, g_repo));
/* ensure that they're all uptodate */
cl_assert((entry = git_index_get_bypath(index, "A", 0)));
cl_assert_equal_i(GIT_INDEX_ENTRY_UPTODATE, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
cl_assert((entry = git_index_get_bypath(index, "B", 0)));
cl_assert_equal_i(GIT_INDEX_ENTRY_UPTODATE, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
cl_assert((entry = git_index_get_bypath(index, "C", 0)));
cl_assert_equal_i(GIT_INDEX_ENTRY_UPTODATE, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
cl_git_pass(git_index_write(index));
git_index_free(index);
}
void test_index_racy__reading_clears_uptodate_bit(void)
{
git_index *index;
const git_index_entry *entry;
setup_uptodate_files();
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_write(index));
cl_git_pass(git_index_read(index, true));
/* ensure that no files are uptodate */
cl_assert((entry = git_index_get_bypath(index, "A", 0)));
cl_assert_equal_i(0, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
cl_assert((entry = git_index_get_bypath(index, "B", 0)));
cl_assert_equal_i(0, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
cl_assert((entry = git_index_get_bypath(index, "C", 0)));
cl_assert_equal_i(0, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
git_index_free(index);
}
void test_index_racy__read_tree_clears_uptodate_bit(void)
{
git_index *index;
git_tree *tree;
const git_index_entry *entry;
git_oid id;
setup_uptodate_files();
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_write_tree_to(&id, index, g_repo));
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
cl_git_pass(git_index_read_tree(index, tree));
/* ensure that no files are uptodate */
cl_assert((entry = git_index_get_bypath(index, "A", 0)));
cl_assert_equal_i(0, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
cl_assert((entry = git_index_get_bypath(index, "B", 0)));
cl_assert_equal_i(0, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
cl_assert((entry = git_index_get_bypath(index, "C", 0)));
cl_assert_equal_i(0, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
git_tree_free(tree);
git_index_free(index);
}
void test_index_racy__read_index_smudges(void)
{
git_index *index, *newindex;
const git_index_entry *entry;
/* if we are reading an index into our new index, ensure that any
* racy entries in the index that we're reading are smudged so that
* we don't propagate their timestamps without further investigation.
*/
setup_race();
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_new(&newindex));
cl_git_pass(git_index_read_index(newindex, index));
cl_assert(entry = git_index_get_bypath(newindex, "A", 0));
cl_assert_equal_i(0, entry->file_size);
git_index_free(index);
git_index_free(newindex);
}
void test_index_racy__read_index_clears_uptodate_bit(void)
{
git_index *index, *newindex;
const git_index_entry *entry;
setup_uptodate_files();
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_new(&newindex));
cl_git_pass(git_index_read_index(newindex, index));
/* ensure that files brought in from the other index are not uptodate */
cl_assert((entry = git_index_get_bypath(newindex, "A", 0)));
cl_assert_equal_i(0, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
cl_assert((entry = git_index_get_bypath(newindex, "B", 0)));
cl_assert_equal_i(0, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
cl_assert((entry = git_index_get_bypath(newindex, "C", 0)));
cl_assert_equal_i(0, (entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE));
git_index_free(index);
git_index_free(newindex);
}
+232
View File
@@ -0,0 +1,232 @@
#include "clar_libgit2.h"
#include "posix.h"
#include "index.h"
#include "conflicts.h"
static git_repository *_repo;
static git_index *_index;
void test_index_read_index__initialize(void)
{
git_object *head;
git_reference *head_ref;
_repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_revparse_ext(&head, &head_ref, _repo, "HEAD"));
cl_git_pass(git_reset(_repo, head, GIT_RESET_HARD, NULL));
cl_git_pass(git_repository_index(&_index, _repo));
git_reference_free(head_ref);
git_object_free(head);
}
void test_index_read_index__cleanup(void)
{
git_index_free(_index);
cl_git_sandbox_cleanup();
}
void test_index_read_index__maintains_stat_cache(void)
{
git_index *new_index;
git_oid index_id;
git_index_entry new_entry;
const git_index_entry *e;
git_tree *tree;
size_t i;
cl_assert_equal_i(4, git_index_entrycount(_index));
/* write-tree */
cl_git_pass(git_index_write_tree(&index_id, _index));
/* read-tree, then read index */
git_tree_lookup(&tree, _repo, &index_id);
cl_git_pass(git_index_new(&new_index));
cl_git_pass(git_index_read_tree(new_index, tree));
git_tree_free(tree);
/* add a new entry that will not have stat data */
memset(&new_entry, 0, sizeof(git_index_entry));
new_entry.path = "Hello";
git_oid_fromstr(&new_entry.id, "0123456789012345678901234567890123456789");
new_entry.file_size = 1234;
new_entry.mode = 0100644;
cl_git_pass(git_index_add(new_index, &new_entry));
cl_assert_equal_i(5, git_index_entrycount(new_index));
cl_git_pass(git_index_read_index(_index, new_index));
git_index_free(new_index);
cl_assert_equal_i(5, git_index_entrycount(_index));
for (i = 0; i < git_index_entrycount(_index); i++) {
e = git_index_get_byindex(_index, i);
if (strcmp(e->path, "Hello") == 0) {
cl_assert_equal_i(0, e->ctime.seconds);
cl_assert_equal_i(0, e->mtime.seconds);
} else {
cl_assert(0 != e->ctime.seconds);
cl_assert(0 != e->mtime.seconds);
}
}
}
static bool roundtrip_with_read_index(const char *tree_idstr)
{
git_oid tree_id, new_tree_id;
git_tree *tree;
git_index *tree_index;
cl_git_pass(git_oid_fromstr(&tree_id, tree_idstr));
cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id));
cl_git_pass(git_index_new(&tree_index));
cl_git_pass(git_index_read_tree(tree_index, tree));
cl_git_pass(git_index_read_index(_index, tree_index));
cl_git_pass(git_index_write_tree(&new_tree_id, _index));
git_tree_free(tree);
git_index_free(tree_index);
return git_oid_equal(&tree_id, &new_tree_id);
}
void test_index_read_index__produces_treesame_indexes(void)
{
roundtrip_with_read_index("53fc32d17276939fc79ed05badaef2db09990016");
roundtrip_with_read_index("944c0f6e4dfa41595e6eb3ceecdb14f50fe18162");
roundtrip_with_read_index("1810dff58d8a660512d4832e740f692884338ccd");
roundtrip_with_read_index("d52a8fe84ceedf260afe4f0287bbfca04a117e83");
roundtrip_with_read_index("c36d8ea75da8cb510fcb0c408c1d7e53f9a99dbe");
roundtrip_with_read_index("7b2417a23b63e1fdde88c80e14b33247c6e5785a");
roundtrip_with_read_index("f82a8eb4cb20e88d1030fd10d89286215a715396");
roundtrip_with_read_index("fd093bff70906175335656e6ce6ae05783708765");
roundtrip_with_read_index("ae90f12eea699729ed24555e40b9fd669da12a12");
}
void test_index_read_index__read_and_writes(void)
{
git_oid tree_id, new_tree_id;
git_tree *tree;
git_index *tree_index, *new_index;
cl_git_pass(git_oid_fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12"));
cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id));
cl_git_pass(git_index_new(&tree_index));
cl_git_pass(git_index_read_tree(tree_index, tree));
cl_git_pass(git_index_read_index(_index, tree_index));
cl_git_pass(git_index_write(_index));
cl_git_pass(git_index_open(&new_index, git_index_path(_index)));
cl_git_pass(git_index_write_tree_to(&new_tree_id, new_index, _repo));
cl_assert_equal_oid(&tree_id, &new_tree_id);
git_tree_free(tree);
git_index_free(tree_index);
git_index_free(new_index);
}
static void add_conflicts(git_index *index, const char *filename)
{
git_index_entry ancestor_entry, our_entry, their_entry;
static int conflict_idx = 0;
char *ancestor_ids[] =
{ CONFLICTS_ONE_ANCESTOR_OID, CONFLICTS_TWO_ANCESTOR_OID };
char *our_ids[] =
{ CONFLICTS_ONE_OUR_OID, CONFLICTS_TWO_OUR_OID };
char *their_ids[] =
{ CONFLICTS_ONE_THEIR_OID, CONFLICTS_TWO_THEIR_OID };
conflict_idx = (conflict_idx + 1) % 2;
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 = filename;
ancestor_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 1);
git_oid_fromstr(&ancestor_entry.id, ancestor_ids[conflict_idx]);
our_entry.path = filename;
our_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 2);
git_oid_fromstr(&our_entry.id, our_ids[conflict_idx]);
their_entry.path = filename;
their_entry.mode = 0100644;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 2);
git_oid_fromstr(&their_entry.id, their_ids[conflict_idx]);
cl_git_pass(git_index_conflict_add(index, &ancestor_entry,
&our_entry, &their_entry));
}
void test_index_read_index__handles_conflicts(void)
{
git_oid tree_id;
git_tree *tree;
git_index *index, *new_index;
git_index_conflict_iterator *conflict_iterator;
const git_index_entry *ancestor, *ours, *theirs;
cl_git_pass(git_oid_fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12"));
cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id));
cl_git_pass(git_index_new(&index));
cl_git_pass(git_index_new(&new_index));
cl_git_pass(git_index_read_tree(index, tree));
cl_git_pass(git_index_read_tree(new_index, tree));
/* put some conflicts in only the old side, these should be removed */
add_conflicts(index, "orig_side-1.txt");
add_conflicts(index, "orig_side-2.txt");
/* put some conflicts in both indexes, these should be unchanged */
add_conflicts(index, "both_sides-1.txt");
add_conflicts(new_index, "both_sides-1.txt");
add_conflicts(index, "both_sides-2.txt");
add_conflicts(new_index, "both_sides-2.txt");
/* put some conflicts in the new index, these should be added */
add_conflicts(new_index, "new_side-1.txt");
add_conflicts(new_index, "new_side-2.txt");
cl_git_pass(git_index_read_index(index, new_index));
cl_git_pass(git_index_conflict_iterator_new(&conflict_iterator, index));
cl_git_pass(git_index_conflict_next(
&ancestor, &ours, &theirs, conflict_iterator));
cl_assert_equal_s("both_sides-1.txt", ancestor->path);
cl_assert_equal_s("both_sides-1.txt", ours->path);
cl_assert_equal_s("both_sides-1.txt", theirs->path);
cl_git_pass(git_index_conflict_next(
&ancestor, &ours, &theirs, conflict_iterator));
cl_assert_equal_s("both_sides-2.txt", ancestor->path);
cl_assert_equal_s("both_sides-2.txt", ours->path);
cl_assert_equal_s("both_sides-2.txt", theirs->path);
cl_git_pass(git_index_conflict_next(
&ancestor, &ours, &theirs, conflict_iterator));
cl_assert_equal_s("new_side-1.txt", ancestor->path);
cl_assert_equal_s("new_side-1.txt", ours->path);
cl_assert_equal_s("new_side-1.txt", theirs->path);
cl_git_pass(git_index_conflict_next(
&ancestor, &ours, &theirs, conflict_iterator));
cl_assert_equal_s("new_side-2.txt", ancestor->path);
cl_assert_equal_s("new_side-2.txt", ours->path);
cl_assert_equal_s("new_side-2.txt", theirs->path);
cl_git_fail_with(GIT_ITEROVER, git_index_conflict_next(
&ancestor, &ours, &theirs, conflict_iterator));
git_index_conflict_iterator_free(conflict_iterator);
git_tree_free(tree);
git_index_free(new_index);
git_index_free(index);
}
+46
View File
@@ -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_equal_oid(&expected, &tree_oid);
git_index_free(index);
git_repository_free(repo);
cl_fixture_cleanup("read_tree");
}
+86
View File
@@ -0,0 +1,86 @@
#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_equal_oid(&expected, &entry->id);
/* 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_equal_oid(&expected, &entry->id);
git_index_free(index);
git_repository_free(repo);
cl_fixture_cleanup("rename");
}
void test_index_rename__casechanging(void)
{
git_repository *repo;
git_index *index;
const git_index_entry *entry;
git_index_entry new = {{0}};
p_mkdir("rename", 0700);
cl_git_pass(git_repository_init(&repo, "./rename", 0));
cl_git_pass(git_repository_index(&index, repo));
cl_git_mkfile("./rename/lame.name.txt", "new_file\n");
cl_git_pass(git_index_add_bypath(index, "lame.name.txt"));
cl_assert_equal_i(1, git_index_entrycount(index));
cl_assert((entry = git_index_get_bypath(index, "lame.name.txt", 0)));
memcpy(&new, entry, sizeof(git_index_entry));
new.path = "LAME.name.TXT";
cl_git_pass(git_index_add(index, &new));
cl_assert((entry = git_index_get_bypath(index, "LAME.name.TXT", 0)));
if (cl_repo_get_bool(repo, "core.ignorecase"))
cl_assert_equal_i(1, git_index_entrycount(index));
else
cl_assert_equal_i(2, git_index_entrycount(index));
git_index_free(index);
git_repository_free(repo);
cl_fixture_cleanup("rename");
}
+376
View File
@@ -0,0 +1,376 @@
#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_equal_oid(&reuc->oid[0], &ancestor_oid);
cl_assert_equal_oid(&reuc->oid[1], &our_oid);
cl_assert_equal_oid(&reuc->oid[2], &their_oid);
cl_git_pass(git_index_write(repo_index));
}
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_equal_oid(&reuc->oid[0], &ancestor_oid);
cl_assert_equal_oid(&reuc->oid[1], &our_oid);
cl_assert_equal_oid(&reuc->oid[2], &their_oid);
cl_git_pass(git_index_write(repo_index));
}
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_equal_oid(&reuc->oid[0], &oid);
git_oid_fromstr(&oid, TWO_OUR_OID);
cl_assert_equal_oid(&reuc->oid[1], &oid);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert_equal_oid(&reuc->oid[2], &oid);
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_equal_oid(&reuc->oid[0], &oid);
git_oid_fromstr(&oid, ONE_OUR_OID);
cl_assert_equal_oid(&reuc->oid[1], &oid);
git_oid_fromstr(&oid, ONE_THEIR_OID);
cl_assert_equal_oid(&reuc->oid[2], &oid);
}
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_INDEX_CAPABILITY_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_INDEX_CAPABILITY_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_equal_oid(&reuc->oid[0], &oid);
git_oid_fromstr(&oid, TWO_OUR_OID);
cl_assert_equal_oid(&reuc->oid[1], &oid);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert_equal_oid(&reuc->oid[2], &oid);
}
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_equal_oid(&reuc->oid[0], &oid);
git_oid_fromstr(&oid, ONE_OUR_OID);
cl_assert_equal_oid(&reuc->oid[1], &oid);
git_oid_fromstr(&oid, ONE_THEIR_OID);
cl_assert_equal_oid(&reuc->oid[2], &oid);
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_equal_oid(&reuc->oid[0], &oid);
git_oid_fromstr(&oid, TWO_OUR_OID);
cl_assert_equal_oid(&reuc->oid[1], &oid);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert_equal_oid(&reuc->oid[2], &oid);
}
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_INDEX_CAPABILITY_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_equal_oid(&reuc->oid[0], &oid);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert_equal_oid(&reuc->oid[1], &oid);
git_oid_fromstr(&oid, TWO_ANCESTOR_OID);
cl_assert_equal_oid(&reuc->oid[2], &oid);
}
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_equal_oid(&reuc->oid[0], &oid);
git_oid_fromstr(&oid, TWO_OUR_OID);
cl_assert_equal_oid(&reuc->oid[1], &oid);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert_equal_oid(&reuc->oid[2], &oid);
}
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;
cl_git_pass(git_revparse_single(&target, repo, "3a34580"));
test_index_reuc__add();
cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL));
cl_assert(reuc_entry_exists() == false);
git_object_free(target);
}
void test_index_reuc__cleaned_on_reset_mixed(void)
{
git_object *target;
cl_git_pass(git_revparse_single(&target, repo, "3a34580"));
test_index_reuc__add();
cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL));
cl_assert(reuc_entry_exists() == false);
git_object_free(target);
}
void test_index_reuc__retained_on_reset_soft(void)
{
git_object *target;
cl_git_pass(git_revparse_single(&target, repo, "3a34580"));
cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL));
test_index_reuc__add();
cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL));
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_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
test_index_reuc__add();
cl_git_pass(git_reference_name_to_id(&oid, repo, "refs/heads/master"));
cl_git_pass(git_object_lookup(&obj, repo, &oid, GIT_OBJECT_ANY));
cl_git_pass(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_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
test_index_reuc__add();
cl_git_pass(git_checkout_head(repo, &opts));
cl_assert(reuc_entry_exists() == false);
}
void test_index_reuc__retained_on_checkout_index(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
test_index_reuc__add();
cl_git_pass(git_checkout_index(repo, repo_index, &opts));
cl_assert(reuc_entry_exists() == true);
}
+21
View File
@@ -0,0 +1,21 @@
#include "clar_libgit2.h"
#include "index.h"
static git_repository *g_repo;
void test_index_splitindex__initialize(void)
{
g_repo = cl_git_sandbox_init("splitindex");
}
void test_index_splitindex__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_index_splitindex__fail_on_open(void)
{
git_index *idx;
cl_git_fail_with(-1, git_repository_index(&idx, g_repo));
cl_assert_equal_s(git_error_last()->message, "unsupported mandatory extension: 'link'");
}
+62
View File
@@ -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);
}
File diff suppressed because it is too large Load Diff
+137
View File
@@ -0,0 +1,137 @@
#include "clar_libgit2.h"
#include "index.h"
static git_repository *g_repo = NULL;
void test_index_version__cleanup(void)
{
cl_git_sandbox_cleanup();
g_repo = NULL;
}
void test_index_version__can_read_v4(void)
{
const char *paths[] = {
"file.tx", "file.txt", "file.txz", "foo", "zzz",
};
git_index *index;
size_t i;
g_repo = cl_git_sandbox_init("indexv4");
cl_git_pass(git_repository_index(&index, g_repo));
cl_assert_equal_sz(git_index_entrycount(index), 5);
for (i = 0; i < ARRAY_SIZE(paths); i++) {
const git_index_entry *entry =
git_index_get_bypath(index, paths[i], GIT_INDEX_STAGE_NORMAL);
cl_assert(entry != NULL);
}
git_index_free(index);
}
void test_index_version__can_write_v4(void)
{
const char *paths[] = {
"foo",
"foox",
"foobar",
"foobal",
"x",
"xz",
"xyzzyx"
};
git_index_entry entry;
git_index *index;
size_t i;
g_repo = cl_git_sandbox_init("empty_standard_repo");
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_set_version(index, 4));
for (i = 0; i < ARRAY_SIZE(paths); i++) {
memset(&entry, 0, sizeof(entry));
entry.path = paths[i];
entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_index_add_from_buffer(index, &entry, paths[i],
strlen(paths[i]) + 1));
}
cl_assert_equal_sz(git_index_entrycount(index), ARRAY_SIZE(paths));
cl_git_pass(git_index_write(index));
git_index_free(index);
cl_git_pass(git_repository_index(&index, g_repo));
cl_assert(git_index_version(index) == 4);
for (i = 0; i < ARRAY_SIZE(paths); i++) {
const git_index_entry *e;
cl_assert(e = git_index_get_bypath(index, paths[i], 0));
cl_assert_equal_s(paths[i], e->path);
}
git_index_free(index);
}
void test_index_version__v4_uses_path_compression(void)
{
git_index_entry entry;
git_index *index;
char path[250], buf[1];
struct stat st;
char i, j;
memset(path, 'a', sizeof(path));
memset(buf, 'a', sizeof(buf));
memset(&entry, 0, sizeof(entry));
entry.path = path;
entry.mode = GIT_FILEMODE_BLOB;
g_repo = cl_git_sandbox_init("indexv4");
cl_git_pass(git_repository_index(&index, g_repo));
/* write 676 paths of 250 bytes length */
for (i = 'a'; i <= 'z'; i++) {
for (j = 'a'; j < 'z'; j++) {
path[ARRAY_SIZE(path) - 3] = i;
path[ARRAY_SIZE(path) - 2] = j;
path[ARRAY_SIZE(path) - 1] = '\0';
cl_git_pass(git_index_add_from_buffer(index, &entry, buf, sizeof(buf)));
}
}
cl_git_pass(git_index_write(index));
cl_git_pass(p_stat(git_index_path(index), &st));
/*
* Without path compression, the written paths would at
* least take
*
* (entries * pathlen) = len
* (676 * 250) = 169000
*
* bytes. As index v4 uses suffix-compression and our
* written paths only differ in the last two entries,
* this number will be much smaller, e.g.
*
* (1 * pathlen) + (675 * 2) = len
* 676 + 1350 = 2026
*
* bytes.
*
* Note that the above calculations do not include
* additional metadata of the index, e.g. OIDs or
* index extensions. Including those we get an index
* of approx. 200kB without compression and 40kB with
* compression. As this is a lot smaller than without
* compression, we can verify that path compression is
* used.
*/
cl_assert_(st.st_size < 75000, "path compression not enabled");
git_index_free(index);
}