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_frombuffer(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); }
void tick_index(git_index *index) { struct timespec ts; struct p_timeval times[2]; cl_assert(index->on_disk); cl_assert(git_index_path(index)); cl_git_pass(git_index_read(index, true)); ts = index->stamp.mtime; times[0].tv_sec = ts.tv_sec; times[0].tv_usec = ts.tv_nsec / 1000; times[1].tv_sec = ts.tv_sec + 5; times[1].tv_usec = ts.tv_nsec / 1000; cl_git_pass(p_utimes(git_index_path(index), times)); cl_git_pass(git_index_read(index, true)); }
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); }
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); }
void test_repo_env__open(void) { git_repository *repo = NULL; git_buf repo_dir_buf = GIT_BUF_INIT; const char *repo_dir = NULL; git_index *index = NULL; const char *t_obj = "testrepo.git/objects"; const char *p_obj = "peeled.git/objects"; clear_git_env(); cl_fixture_sandbox("attr"); cl_fixture_sandbox("testrepo.git"); cl_fixture_sandbox("peeled.git"); cl_git_pass(p_rename("attr/.gitted", "attr/.git")); cl_git_pass(git_path_prettify_dir(&repo_dir_buf, "attr", NULL)); repo_dir = git_buf_cstr(&repo_dir_buf); /* GIT_DIR that doesn't exist */ cl_setenv("GIT_DIR", "does-not-exist"); env_fail(NULL); /* Explicit start_path overrides GIT_DIR */ env_pass("attr"); env_pass("attr/.git"); env_pass("attr/sub"); env_pass("attr/sub/sub"); /* GIT_DIR with relative paths */ cl_setenv("GIT_DIR", "attr/.git"); env_pass(NULL); cl_setenv("GIT_DIR", "attr"); env_fail(NULL); cl_setenv("GIT_DIR", "attr/sub"); env_fail(NULL); cl_setenv("GIT_DIR", "attr/sub/sub"); env_fail(NULL); /* GIT_DIR with absolute paths */ cl_setenv_printf("GIT_DIR", "%s/.git", repo_dir); env_pass(NULL); cl_setenv("GIT_DIR", repo_dir); env_fail(NULL); cl_setenv_printf("GIT_DIR", "%s/sub", repo_dir); env_fail(NULL); cl_setenv_printf("GIT_DIR", "%s/sub/sub", repo_dir); env_fail(NULL); cl_setenv("GIT_DIR", NULL); /* Searching from the current directory */ env_cd_pass("attr"); env_cd_pass("attr/.git"); env_cd_pass("attr/sub"); env_cd_pass("attr/sub/sub"); /* A ceiling directory blocks searches from ascending into that * directory, but doesn't block the start_path itself. */ cl_setenv("GIT_CEILING_DIRECTORIES", repo_dir); env_cd_pass("attr"); env_cd_fail("attr/sub"); env_cd_fail("attr/sub/sub"); cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s/sub", repo_dir); env_cd_pass("attr"); env_cd_pass("attr/sub"); env_cd_fail("attr/sub/sub"); /* Multiple ceiling directories */ cl_setenv_printf("GIT_CEILING_DIRECTORIES", "123%c%s/sub%cabc", GIT_PATH_LIST_SEPARATOR, repo_dir, GIT_PATH_LIST_SEPARATOR); env_cd_pass("attr"); env_cd_pass("attr/sub"); env_cd_fail("attr/sub/sub"); cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s%c%s/sub", repo_dir, GIT_PATH_LIST_SEPARATOR, repo_dir); env_cd_pass("attr"); env_cd_fail("attr/sub"); env_cd_fail("attr/sub/sub"); cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s/sub%c%s", repo_dir, GIT_PATH_LIST_SEPARATOR, repo_dir); env_cd_pass("attr"); env_cd_fail("attr/sub"); env_cd_fail("attr/sub/sub"); cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s%c%s/sub/sub", repo_dir, GIT_PATH_LIST_SEPARATOR, repo_dir); env_cd_pass("attr"); env_cd_fail("attr/sub"); env_cd_fail("attr/sub/sub"); cl_setenv("GIT_CEILING_DIRECTORIES", NULL); /* Index files */ cl_setenv("GIT_INDEX_FILE", cl_fixture("gitgit.index")); cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL)); cl_git_pass(git_repository_index(&index, repo)); cl_assert_equal_s(git_index_path(index), cl_fixture("gitgit.index")); cl_assert_equal_i(git_index_entrycount(index), 1437); git_index_free(index); git_repository_free(repo); cl_setenv("GIT_INDEX_FILE", NULL); /* Namespaces */ cl_setenv("GIT_NAMESPACE", "some-namespace"); cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL)); cl_assert_equal_s(git_repository_get_namespace(repo), "some-namespace"); git_repository_free(repo); cl_setenv("GIT_NAMESPACE", NULL); /* Object directories and alternates */ env_check_objects(true, false, false); cl_setenv("GIT_OBJECT_DIRECTORY", t_obj); env_check_objects(false, true, false); cl_setenv("GIT_OBJECT_DIRECTORY", NULL); cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", t_obj); env_check_objects(true, true, false); cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL); cl_setenv("GIT_OBJECT_DIRECTORY", p_obj); env_check_objects(false, false, true); cl_setenv("GIT_OBJECT_DIRECTORY", NULL); cl_setenv("GIT_OBJECT_DIRECTORY", t_obj); cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", p_obj); env_check_objects(false, true, true); cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL); cl_setenv("GIT_OBJECT_DIRECTORY", NULL); cl_setenv_printf("GIT_ALTERNATE_OBJECT_DIRECTORIES", "%s%c%s", t_obj, GIT_PATH_LIST_SEPARATOR, p_obj); env_check_objects(true, true, true); cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL); cl_setenv_printf("GIT_ALTERNATE_OBJECT_DIRECTORIES", "%s%c%s", p_obj, GIT_PATH_LIST_SEPARATOR, t_obj); env_check_objects(true, true, true); cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL); cl_fixture_cleanup("peeled.git"); cl_fixture_cleanup("testrepo.git"); cl_fixture_cleanup("attr"); git_buf_free(&repo_dir_buf); clear_git_env(); }