Initial commit - full huishou project

This commit is contained in:
jiapengyu
2026-07-27 14:07:26 +08:00
commit 60790ad1b3
39127 changed files with 5989265 additions and 0 deletions
+211
View File
@@ -0,0 +1,211 @@
#include "clar_libgit2.h"
#include "sysdir.h"
#include "futils.h"
#include <ctype.h>
static git_buf path = GIT_BUF_INIT;
void test_repo_config__initialize(void)
{
cl_fixture_sandbox("empty_standard_repo");
cl_git_pass(cl_rename(
"empty_standard_repo/.gitted", "empty_standard_repo/.git"));
git_buf_clear(&path);
cl_must_pass(p_mkdir("alternate", 0777));
cl_git_pass(git_path_prettify(&path, "alternate", NULL));
}
void test_repo_config__cleanup(void)
{
cl_sandbox_set_search_path_defaults();
git_buf_dispose(&path);
cl_git_pass(
git_futils_rmdir_r("alternate", NULL, GIT_RMDIR_REMOVE_FILES));
cl_assert(!git_path_isdir("alternate"));
cl_fixture_cleanup("empty_standard_repo");
}
void test_repo_config__can_open_global_when_there_is_no_file(void)
{
git_repository *repo;
git_config *config, *global;
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
cl_git_pass(git_repository_config(&config, repo));
cl_git_pass(git_config_open_level(
&global, config, GIT_CONFIG_LEVEL_GLOBAL));
cl_git_pass(git_config_set_string(global, "test.set", "42"));
git_config_free(global);
git_config_free(config);
git_repository_free(repo);
}
void test_repo_config__can_open_missing_global_with_separators(void)
{
git_repository *repo;
git_config *config, *global;
cl_git_pass(git_buf_printf(
&path, "%c%s", GIT_PATH_LIST_SEPARATOR, "dummy"));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
git_buf_dispose(&path);
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
cl_git_pass(git_repository_config(&config, repo));
cl_git_pass(git_config_open_level(
&global, config, GIT_CONFIG_LEVEL_GLOBAL));
cl_git_pass(git_config_set_string(global, "test.set", "42"));
git_config_free(global);
git_config_free(config);
git_repository_free(repo);
}
#include "repository.h"
void test_repo_config__read_with_no_configs_at_all(void)
{
git_repository *repo;
int val;
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
/* with none */
cl_must_pass(p_unlink("empty_standard_repo/.git/config"));
cl_assert(!git_path_isfile("empty_standard_repo/.git/config"));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
git_repository__configmap_lookup_cache_clear(repo);
val = -1;
cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(GIT_ABBREV_DEFAULT, val);
git_repository_free(repo);
/* with no local config, just system */
cl_sandbox_set_search_path_defaults();
cl_must_pass(p_mkdir("alternate/1", 0777));
cl_git_pass(git_buf_joinpath(&path, path.ptr, "1"));
cl_git_rewritefile("alternate/1/gitconfig", "[core]\n\tabbrev = 10\n");
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
git_repository__configmap_lookup_cache_clear(repo);
val = -1;
cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(10, val);
git_repository_free(repo);
/* with just xdg + system */
cl_must_pass(p_mkdir("alternate/2", 0777));
path.ptr[path.size - 1] = '2';
cl_git_rewritefile("alternate/2/config", "[core]\n\tabbrev = 20\n");
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
git_repository__configmap_lookup_cache_clear(repo);
val = -1;
cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(20, val);
git_repository_free(repo);
/* with global + xdg + system */
cl_must_pass(p_mkdir("alternate/3", 0777));
path.ptr[path.size - 1] = '3';
cl_git_rewritefile("alternate/3/.gitconfig", "[core]\n\tabbrev = 30\n");
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
git_repository__configmap_lookup_cache_clear(repo);
val = -1;
cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(30, val);
git_repository_free(repo);
/* with all configs */
cl_git_rewritefile("empty_standard_repo/.git/config", "[core]\n\tabbrev = 40\n");
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
git_repository__configmap_lookup_cache_clear(repo);
val = -1;
cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(40, val);
git_repository_free(repo);
/* with all configs but delete the files ? */
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
git_repository__configmap_lookup_cache_clear(repo);
val = -1;
cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(40, val);
cl_must_pass(p_unlink("empty_standard_repo/.git/config"));
cl_assert(!git_path_isfile("empty_standard_repo/.git/config"));
cl_must_pass(p_unlink("alternate/1/gitconfig"));
cl_assert(!git_path_isfile("alternate/1/gitconfig"));
cl_must_pass(p_unlink("alternate/2/config"));
cl_assert(!git_path_isfile("alternate/2/config"));
cl_must_pass(p_unlink("alternate/3/.gitconfig"));
cl_assert(!git_path_isfile("alternate/3/.gitconfig"));
git_repository__configmap_lookup_cache_clear(repo);
val = -1;
cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(40, val);
git_repository_free(repo);
/* reopen */
cl_assert(!git_path_isfile("empty_standard_repo/.git/config"));
cl_assert(!git_path_isfile("alternate/3/.gitconfig"));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
git_repository__configmap_lookup_cache_clear(repo);
val = -1;
cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(7, val);
git_repository_free(repo);
cl_assert(!git_path_exists("empty_standard_repo/.git/config"));
cl_assert(!git_path_exists("alternate/3/.gitconfig"));
}
+210
View File
@@ -0,0 +1,210 @@
#include "clar_libgit2.h"
#include "odb.h"
#include "futils.h"
#include "repository.h"
#define TEMP_REPO_FOLDER "temprepo/"
#define DISCOVER_FOLDER TEMP_REPO_FOLDER "discover.git"
#define SUB_REPOSITORY_FOLDER_NAME "sub_repo"
#define SUB_REPOSITORY_FOLDER DISCOVER_FOLDER "/" SUB_REPOSITORY_FOLDER_NAME
#define SUB_REPOSITORY_GITDIR SUB_REPOSITORY_FOLDER "/.git"
#define SUB_REPOSITORY_FOLDER_SUB SUB_REPOSITORY_FOLDER "/sub"
#define SUB_REPOSITORY_FOLDER_SUB_SUB SUB_REPOSITORY_FOLDER_SUB "/subsub"
#define SUB_REPOSITORY_FOLDER_SUB_SUB_SUB SUB_REPOSITORY_FOLDER_SUB_SUB "/subsubsub"
#define REPOSITORY_ALTERNATE_FOLDER DISCOVER_FOLDER "/alternate_sub_repo"
#define REPOSITORY_ALTERNATE_FOLDER_SUB REPOSITORY_ALTERNATE_FOLDER "/sub"
#define REPOSITORY_ALTERNATE_FOLDER_SUB_SUB REPOSITORY_ALTERNATE_FOLDER_SUB "/subsub"
#define REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/subsubsub"
#define ALTERNATE_MALFORMED_FOLDER1 DISCOVER_FOLDER "/alternate_malformed_repo1"
#define ALTERNATE_MALFORMED_FOLDER2 DISCOVER_FOLDER "/alternate_malformed_repo2"
#define ALTERNATE_MALFORMED_FOLDER3 DISCOVER_FOLDER "/alternate_malformed_repo3"
#define ALTERNATE_NOT_FOUND_FOLDER DISCOVER_FOLDER "/alternate_not_found_repo"
static void ensure_repository_discover(const char *start_path,
const char *ceiling_dirs,
const char *expected_path)
{
git_buf found_path = GIT_BUF_INIT, resolved = GIT_BUF_INIT;
git_buf_attach(&resolved, p_realpath(expected_path, NULL), 0);
cl_assert(resolved.size > 0);
cl_git_pass(git_path_to_dir(&resolved));
cl_git_pass(git_repository_discover(&found_path, start_path, 1, ceiling_dirs));
cl_assert_equal_s(found_path.ptr, resolved.ptr);
git_buf_dispose(&resolved);
git_buf_dispose(&found_path);
}
static void write_file(const char *path, const char *content)
{
git_file file;
int error;
if (git_path_exists(path)) {
cl_git_pass(p_unlink(path));
}
file = git_futils_creat_withpath(path, 0777, 0666);
cl_assert(file >= 0);
error = p_write(file, content, strlen(content) * sizeof(char));
p_close(file);
cl_git_pass(error);
}
/*no check is performed on ceiling_dirs length, so be sure it's long enough */
static void append_ceiling_dir(git_buf *ceiling_dirs, const char *path)
{
git_buf pretty_path = GIT_BUF_INIT;
char ceiling_separator[2] = { GIT_PATH_LIST_SEPARATOR, '\0' };
cl_git_pass(git_path_prettify_dir(&pretty_path, path, NULL));
if (ceiling_dirs->size > 0)
git_buf_puts(ceiling_dirs, ceiling_separator);
git_buf_puts(ceiling_dirs, pretty_path.ptr);
git_buf_dispose(&pretty_path);
cl_assert(git_buf_oom(ceiling_dirs) == 0);
}
static git_buf discovered;
static git_buf ceiling_dirs;
void test_repo_discover__initialize(void)
{
git_repository *repo;
const mode_t mode = 0777;
git_futils_mkdir_r(DISCOVER_FOLDER, mode);
git_buf_init(&discovered, 0);
git_buf_init(&ceiling_dirs, 0);
append_ceiling_dir(&ceiling_dirs, TEMP_REPO_FOLDER);
cl_git_pass(git_repository_init(&repo, DISCOVER_FOLDER, 1));
git_repository_free(repo);
cl_git_pass(git_repository_init(&repo, SUB_REPOSITORY_FOLDER, 0));
cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode));
cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode));
cl_git_pass(git_futils_mkdir_r(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, mode));
write_file(REPOSITORY_ALTERNATE_FOLDER "/" DOT_GIT, "gitdir: ../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT);
write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/" DOT_GIT, "gitdir: ../../../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT);
write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB "/" DOT_GIT, "gitdir: ../../../../");
cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER1, mode));
write_file(ALTERNATE_MALFORMED_FOLDER1 "/" DOT_GIT, "Anything but not gitdir:");
cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER2, mode));
write_file(ALTERNATE_MALFORMED_FOLDER2 "/" DOT_GIT, "gitdir:");
cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER3, mode));
write_file(ALTERNATE_MALFORMED_FOLDER3 "/" DOT_GIT, "gitdir: \n\n\n");
cl_git_pass(git_futils_mkdir_r(ALTERNATE_NOT_FOUND_FOLDER, mode));
write_file(ALTERNATE_NOT_FOUND_FOLDER "/" DOT_GIT, "gitdir: a_repository_that_surely_does_not_exist");
git_repository_free(repo);
}
void test_repo_discover__cleanup(void)
{
git_buf_dispose(&discovered);
git_buf_dispose(&ceiling_dirs);
cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_RMDIR_REMOVE_FILES));
}
void test_repo_discover__discovering_repo_with_exact_path_succeeds(void)
{
cl_git_pass(git_repository_discover(&discovered, DISCOVER_FOLDER, 0, ceiling_dirs.ptr));
cl_git_pass(git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs.ptr));
}
void test_repo_discover__discovering_nonexistent_dir_fails(void)
{
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, DISCOVER_FOLDER "-nonexistent", 0, NULL));
}
void test_repo_discover__discovering_repo_with_subdirectory_succeeds(void)
{
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
}
void test_repo_discover__discovering_repository_with_alternative_gitdir_succeeds(void)
{
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, DISCOVER_FOLDER);
}
void test_repo_discover__discovering_repository_with_malformed_alternative_gitdir_fails(void)
{
cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs.ptr));
cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs.ptr));
cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs.ptr));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs.ptr));
}
void test_repo_discover__discovering_repository_with_ceiling(void)
{
append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER_SUB);
/* this must pass as ceiling_directories cannot prevent the current
* working directory to be checked */
ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs.ptr));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs.ptr));
}
void test_repo_discover__other_ceiling(void)
{
append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER);
/* this must pass as ceiling_directories cannot predent the current
* working directory to be checked */
ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs.ptr));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs.ptr));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs.ptr));
}
void test_repo_discover__ceiling_should_not_affect_gitdir_redirection(void)
{
append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER);
/* gitfile redirection should not be affected by ceiling directories */
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, DISCOVER_FOLDER);
}
void test_repo_discover__discovery_starting_at_file_succeeds(void)
{
int fd;
cl_assert((fd = p_creat(SUB_REPOSITORY_FOLDER "/file", 0600)) >= 0);
cl_assert(p_close(fd) == 0);
ensure_repository_discover(SUB_REPOSITORY_FOLDER "/file", ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
}
void test_repo_discover__discovery_starting_at_system_root_causes_no_hang(void)
{
#ifdef GIT_WIN32
git_buf out = GIT_BUF_INIT;
cl_git_fail(git_repository_discover(&out, "C:/", 0, NULL));
cl_git_fail(git_repository_discover(&out, "//localhost/", 0, NULL));
#endif
}
+277
View File
@@ -0,0 +1,277 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "sysdir.h"
#include <ctype.h>
static void clear_git_env(void)
{
cl_setenv("GIT_DIR", NULL);
cl_setenv("GIT_CEILING_DIRECTORIES", NULL);
cl_setenv("GIT_INDEX_FILE", NULL);
cl_setenv("GIT_NAMESPACE", NULL);
cl_setenv("GIT_OBJECT_DIRECTORY", NULL);
cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);
cl_setenv("GIT_WORK_TREE", NULL);
cl_setenv("GIT_COMMON_DIR", NULL);
}
void test_repo_env__initialize(void)
{
clear_git_env();
}
void test_repo_env__cleanup(void)
{
cl_git_sandbox_cleanup();
if (git_path_isdir("attr"))
git_futils_rmdir_r("attr", NULL, GIT_RMDIR_REMOVE_FILES);
if (git_path_isdir("testrepo.git"))
git_futils_rmdir_r("testrepo.git", NULL, GIT_RMDIR_REMOVE_FILES);
if (git_path_isdir("peeled.git"))
git_futils_rmdir_r("peeled.git", NULL, GIT_RMDIR_REMOVE_FILES);
clear_git_env();
}
static int GIT_FORMAT_PRINTF(2, 3) cl_setenv_printf(const char *name, const char *fmt, ...)
{
int ret;
va_list args;
git_buf buf = GIT_BUF_INIT;
va_start(args, fmt);
cl_git_pass(git_buf_vprintf(&buf, fmt, args));
va_end(args);
ret = cl_setenv(name, git_buf_cstr(&buf));
git_buf_dispose(&buf);
return ret;
}
/* Helper functions for test_repo_open__env, passing through the file and line
* from the caller rather than those of the helper. The expression strings
* distinguish between the possible failures within the helper. */
static void env_pass_(const char *path, const char *file, int line)
{
git_repository *repo;
cl_git_expect(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line);
cl_git_expect(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line);
cl_assert_at_line(git__suffixcmp(git_repository_path(repo), "attr/.git/") == 0, file, line);
cl_assert_at_line(git__suffixcmp(git_repository_workdir(repo), "attr/") == 0, file, line);
cl_assert_at_line(!git_repository_is_bare(repo), file, line);
git_repository_free(repo);
}
#define env_pass(path) env_pass_((path), __FILE__, __LINE__)
#define cl_git_fail_at_line(expr, file, line) clar__assert((expr) < 0, file, line, "Expected function call to fail: " #expr, NULL, 1)
static void env_fail_(const char *path, const char *file, int line)
{
git_repository *repo;
cl_git_fail_at_line(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
cl_git_fail_at_line(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
}
#define env_fail(path) env_fail_((path), __FILE__, __LINE__)
static void env_cd_(
const char *path,
void (*passfail_)(const char *, const char *, int),
const char *file, int line)
{
git_buf cwd_buf = GIT_BUF_INIT;
cl_git_pass(git_path_prettify_dir(&cwd_buf, ".", NULL));
cl_must_pass(p_chdir(path));
passfail_(NULL, file, line);
cl_must_pass(p_chdir(git_buf_cstr(&cwd_buf)));
git_buf_dispose(&cwd_buf);
}
#define env_cd_pass(path) env_cd_((path), env_pass_, __FILE__, __LINE__)
#define env_cd_fail(path) env_cd_((path), env_fail_, __FILE__, __LINE__)
static void env_check_objects_(bool a, bool t, bool p, const char *file, int line)
{
git_repository *repo;
git_oid oid_a, oid_t, oid_p;
git_object *object;
cl_git_pass(git_oid_fromstr(&oid_a, "45141a79a77842c59a63229403220a4e4be74e3d"));
cl_git_pass(git_oid_fromstr(&oid_t, "1385f264afb75a56a5bec74243be9b367ba4ca08"));
cl_git_pass(git_oid_fromstr(&oid_p, "0df1a5865c8abfc09f1f2182e6a31be550e99f07"));
cl_git_expect(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line);
if (a) {
cl_git_expect(git_object_lookup(&object, repo, &oid_a, GIT_OBJECT_BLOB), 0, file, line);
git_object_free(object);
} else {
cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_a, GIT_OBJECT_BLOB), file, line);
}
if (t) {
cl_git_expect(git_object_lookup(&object, repo, &oid_t, GIT_OBJECT_BLOB), 0, file, line);
git_object_free(object);
} else {
cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_t, GIT_OBJECT_BLOB), file, line);
}
if (p) {
cl_git_expect(git_object_lookup(&object, repo, &oid_p, GIT_OBJECT_COMMIT), 0, file, line);
git_object_free(object);
} else {
cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_p, GIT_OBJECT_COMMIT), file, line);
}
git_repository_free(repo);
}
#define env_check_objects(a, t, t2) env_check_objects_((a), (t), (t2), __FILE__, __LINE__)
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_dispose(&repo_dir_buf);
clear_git_env();
}
+40
View File
@@ -0,0 +1,40 @@
#include "clar_libgit2.h"
void test_repo_getters__is_empty_correctly_deals_with_pristine_looking_repos(void)
{
git_repository *repo;
repo = cl_git_sandbox_init("empty_bare.git");
cl_git_remove_placeholders(git_repository_path(repo), "dummy-marker.txt");
cl_assert_equal_i(true, git_repository_is_empty(repo));
cl_git_sandbox_cleanup();
}
void test_repo_getters__is_empty_can_detect_used_repositories(void)
{
git_repository *repo;
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
cl_assert_equal_i(false, git_repository_is_empty(repo));
git_repository_free(repo);
}
void test_repo_getters__retrieving_the_odb_honors_the_refcount(void)
{
git_odb *odb;
git_repository *repo;
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
cl_git_pass(git_repository_odb(&odb, repo));
cl_assert(((git_refcount *)odb)->refcount.val == 2);
git_repository_free(repo);
cl_assert(((git_refcount *)odb)->refcount.val == 1);
git_odb_free(odb);
}
+85
View File
@@ -0,0 +1,85 @@
#include "clar_libgit2.h"
#include "buffer.h"
static git_repository *_repo;
void test_repo_hashfile__initialize(void)
{
_repo = cl_git_sandbox_init("status");
}
void test_repo_hashfile__cleanup(void)
{
cl_git_sandbox_cleanup();
_repo = NULL;
}
void test_repo_hashfile__simple(void)
{
git_oid a, b;
git_buf full = GIT_BUF_INIT;
/* hash with repo relative path */
cl_git_pass(git_odb_hashfile(&a, "status/current_file", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "current_file", GIT_OBJECT_BLOB, NULL));
cl_assert_equal_oid(&a, &b);
cl_git_pass(git_buf_joinpath(&full, git_repository_workdir(_repo), "current_file"));
/* hash with full path */
cl_git_pass(git_odb_hashfile(&a, full.ptr, GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, full.ptr, GIT_OBJECT_BLOB, NULL));
cl_assert_equal_oid(&a, &b);
/* hash with invalid type */
cl_git_fail(git_odb_hashfile(&a, full.ptr, GIT_OBJECT_ANY));
cl_git_fail(git_repository_hashfile(&b, _repo, full.ptr, GIT_OBJECT_OFS_DELTA, NULL));
git_buf_dispose(&full);
}
void test_repo_hashfile__filtered(void)
{
git_oid a, b;
cl_repo_set_bool(_repo, "core.autocrlf", true);
cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n");
/* create some sample content with CRLF in it */
cl_git_mkfile("status/testfile.txt", "content\r\n");
cl_git_mkfile("status/testfile.bin", "other\r\nstuff\r\n");
/* not equal hashes because of filtering */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, NULL));
cl_assert(git_oid_cmp(&a, &b));
/* equal hashes because filter is binary */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, NULL));
cl_assert_equal_oid(&a, &b);
/* equal hashes when 'as_file' points to binary filtering */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, "foo.bin"));
cl_assert_equal_oid(&a, &b);
/* not equal hashes when 'as_file' points to text filtering */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, "foo.txt"));
cl_assert(git_oid_cmp(&a, &b));
/* equal hashes when 'as_file' is empty and turns off filtering */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, ""));
cl_assert_equal_oid(&a, &b);
cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, ""));
cl_assert_equal_oid(&a, &b);
/* some hash type failures */
cl_git_fail(git_odb_hashfile(&a, "status/testfile.txt", 0));
cl_git_fail(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_ANY, NULL));
}
+182
View File
@@ -0,0 +1,182 @@
#include "clar_libgit2.h"
#include "refs.h"
#include "repo_helpers.h"
#include "posix.h"
#include "git2/annotated_commit.h"
static const char *g_email = "foo@example.com";
static git_repository *repo;
void test_repo_head__initialize(void)
{
repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_repository_set_ident(repo, "Foo Bar", g_email));
}
void test_repo_head__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_repo_head__unborn_head(void)
{
git_reference *ref;
cl_git_pass(git_repository_head_detached(repo));
make_head_unborn(repo, NON_EXISTING_HEAD);
cl_assert(git_repository_head_unborn(repo) == 1);
/* take the repo back to it's original state */
cl_git_pass(git_reference_symbolic_create(&ref, repo, "HEAD", "refs/heads/master", 1, NULL));
cl_assert(git_repository_head_unborn(repo) == 0);
git_reference_free(ref);
}
void test_repo_head__set_head_Attaches_HEAD_to_un_unborn_branch_when_the_branch_doesnt_exist(void)
{
git_reference *head;
cl_git_pass(git_repository_set_head(repo, "refs/heads/doesnt/exist/yet"));
cl_assert_equal_i(false, git_repository_head_detached(repo));
cl_assert_equal_i(GIT_EUNBORNBRANCH, git_repository_head(&head, repo));
}
void test_repo_head__set_head_Returns_ENOTFOUND_when_the_reference_doesnt_exist(void)
{
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_set_head(repo, "refs/tags/doesnt/exist/yet"));
}
void test_repo_head__set_head_Fails_when_the_reference_points_to_a_non_commitish(void)
{
cl_git_fail(git_repository_set_head(repo, "refs/tags/point_to_blob"));
}
void test_repo_head__set_head_Attaches_HEAD_when_the_reference_points_to_a_branch(void)
{
git_reference *head;
cl_git_pass(git_repository_set_head(repo, "refs/heads/br2"));
cl_assert_equal_i(false, git_repository_head_detached(repo));
cl_git_pass(git_repository_head(&head, repo));
cl_assert_equal_s("refs/heads/br2", git_reference_name(head));
git_reference_free(head);
}
static void assert_head_is_correctly_detached(void)
{
git_reference *head;
git_object *commit;
cl_assert_equal_i(true, git_repository_head_detached(repo));
cl_git_pass(git_repository_head(&head, repo));
cl_git_pass(git_object_lookup(&commit, repo, git_reference_target(head), GIT_OBJECT_COMMIT));
git_object_free(commit);
git_reference_free(head);
}
void test_repo_head__set_head_Detaches_HEAD_when_the_reference_doesnt_point_to_a_branch(void)
{
cl_git_pass(git_repository_set_head(repo, "refs/tags/test"));
cl_assert_equal_i(true, git_repository_head_detached(repo));
assert_head_is_correctly_detached();
}
void test_repo_head__set_head_detached_Return_ENOTFOUND_when_the_object_doesnt_exist(void)
{
git_oid oid;
cl_git_pass(git_oid_fromstr(&oid, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_set_head_detached(repo, &oid));
}
void test_repo_head__set_head_detached_Fails_when_the_object_isnt_a_commitish(void)
{
git_object *blob;
cl_git_pass(git_revparse_single(&blob, repo, "point_to_blob"));
cl_git_fail(git_repository_set_head_detached(repo, git_object_id(blob)));
git_object_free(blob);
}
void test_repo_head__set_head_detached_Detaches_HEAD_and_make_it_point_to_the_peeled_commit(void)
{
git_object *tag;
cl_git_pass(git_revparse_single(&tag, repo, "tags/test"));
cl_assert_equal_i(GIT_OBJECT_TAG, git_object_type(tag));
cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag)));
assert_head_is_correctly_detached();
git_object_free(tag);
}
void test_repo_head__detach_head_Detaches_HEAD_and_make_it_point_to_the_peeled_commit(void)
{
cl_assert_equal_i(false, git_repository_head_detached(repo));
cl_git_pass(git_repository_detach_head(repo));
assert_head_is_correctly_detached();
}
void test_repo_head__detach_head_Fails_if_HEAD_and_point_to_a_non_commitish(void)
{
git_reference *head;
cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, "refs/tags/point_to_blob", 1, NULL));
cl_git_fail(git_repository_detach_head(repo));
git_reference_free(head);
}
void test_repo_head__detaching_an_unborn_branch_returns_GIT_EUNBORNBRANCH(void)
{
make_head_unborn(repo, NON_EXISTING_HEAD);
cl_assert_equal_i(GIT_EUNBORNBRANCH, git_repository_detach_head(repo));
}
void test_repo_head__retrieving_an_unborn_branch_returns_GIT_EUNBORNBRANCH(void)
{
git_reference *head;
make_head_unborn(repo, NON_EXISTING_HEAD);
cl_assert_equal_i(GIT_EUNBORNBRANCH, git_repository_head(&head, repo));
}
void test_repo_head__retrieving_a_missing_head_returns_GIT_ENOTFOUND(void)
{
git_reference *head;
delete_head(repo);
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_head(&head, repo));
}
void test_repo_head__can_tell_if_an_unborn_head_is_detached(void)
{
make_head_unborn(repo, NON_EXISTING_HEAD);
cl_assert_equal_i(false, git_repository_head_detached(repo));
}
+53
View File
@@ -0,0 +1,53 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "repo_helpers.h"
#include "posix.h"
static git_repository *repo;
static git_tree *tree;
void test_repo_headtree__initialize(void)
{
repo = cl_git_sandbox_init("testrepo.git");
tree = NULL;
}
void test_repo_headtree__cleanup(void)
{
git_tree_free(tree);
cl_git_sandbox_cleanup();
}
void test_repo_headtree__can_retrieve_the_root_tree_from_a_detached_head(void)
{
cl_git_pass(git_repository_detach_head(repo));
cl_git_pass(git_repository_head_tree(&tree, repo));
cl_assert(git_oid_streq(git_tree_id(tree), "az"));
}
void test_repo_headtree__can_retrieve_the_root_tree_from_a_non_detached_head(void)
{
cl_assert_equal_i(false, git_repository_head_detached(repo));
cl_git_pass(git_repository_head_tree(&tree, repo));
cl_assert(git_oid_streq(git_tree_id(tree), "az"));
}
void test_repo_headtree__when_head_is_unborn_returns_EUNBORNBRANCH(void)
{
make_head_unborn(repo, NON_EXISTING_HEAD);
cl_assert_equal_i(true, git_repository_head_unborn(repo));
cl_assert_equal_i(GIT_EUNBORNBRANCH, git_repository_head_tree(&tree, repo));
}
void test_repo_headtree__when_head_is_missing_returns_ENOTFOUND(void)
{
delete_head(repo);
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_head_tree(&tree, repo));
}
+667
View File
@@ -0,0 +1,667 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "repository.h"
#include "config.h"
#include "path.h"
#include "config/config_helpers.h"
#include "repo/repo_helpers.h"
enum repo_mode {
STANDARD_REPOSITORY = 0,
BARE_REPOSITORY = 1
};
static git_repository *_repo = NULL;
static git_buf _global_path = GIT_BUF_INIT;
void test_repo_init__initialize(void)
{
_repo = NULL;
git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
&_global_path);
}
void test_repo_init__cleanup(void)
{
git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
_global_path.ptr);
git_buf_dispose(&_global_path);
cl_fixture_cleanup("tmp_global_path");
}
static void cleanup_repository(void *path)
{
git_repository_free(_repo);
_repo = NULL;
cl_fixture_cleanup((const char *)path);
}
static void ensure_repository_init(
const char *working_directory,
int is_bare,
const char *expected_path_repository,
const char *expected_working_directory)
{
const char *workdir;
cl_assert(!git_path_isdir(working_directory));
cl_git_pass(git_repository_init(&_repo, working_directory, is_bare));
workdir = git_repository_workdir(_repo);
if (workdir != NULL || expected_working_directory != NULL) {
cl_assert(
git__suffixcmp(workdir, expected_working_directory) == 0
);
}
cl_assert(
git__suffixcmp(git_repository_path(_repo), expected_path_repository) == 0
);
cl_assert(git_repository_is_bare(_repo) == is_bare);
#ifdef GIT_WIN32
if (!is_bare) {
DWORD fattrs = GetFileAttributes(git_repository_path(_repo));
cl_assert((fattrs & FILE_ATTRIBUTE_HIDDEN) != 0);
}
#endif
cl_assert(git_repository_is_empty(_repo));
}
void test_repo_init__standard_repo(void)
{
cl_set_cleanup(&cleanup_repository, "testrepo");
ensure_repository_init("testrepo/", 0, "testrepo/.git/", "testrepo/");
}
void test_repo_init__standard_repo_noslash(void)
{
cl_set_cleanup(&cleanup_repository, "testrepo");
ensure_repository_init("testrepo", 0, "testrepo/.git/", "testrepo/");
}
void test_repo_init__bare_repo(void)
{
cl_set_cleanup(&cleanup_repository, "testrepo.git");
ensure_repository_init("testrepo.git/", 1, "testrepo.git/", NULL);
}
void test_repo_init__bare_repo_noslash(void)
{
cl_set_cleanup(&cleanup_repository, "testrepo.git");
ensure_repository_init("testrepo.git", 1, "testrepo.git/", NULL);
}
void test_repo_init__bare_repo_escaping_current_workdir(void)
{
git_buf path_repository = GIT_BUF_INIT;
git_buf path_current_workdir = GIT_BUF_INIT;
cl_git_pass(git_path_prettify_dir(&path_current_workdir, ".", NULL));
cl_git_pass(git_buf_joinpath(&path_repository, git_buf_cstr(&path_current_workdir), "a/b/c"));
cl_git_pass(git_futils_mkdir_r(git_buf_cstr(&path_repository), GIT_DIR_MODE));
/* Change the current working directory */
cl_git_pass(chdir(git_buf_cstr(&path_repository)));
/* Initialize a bare repo with a relative path escaping out of the current working directory */
cl_git_pass(git_repository_init(&_repo, "../d/e.git", 1));
cl_git_pass(git__suffixcmp(git_repository_path(_repo), "/a/b/d/e.git/"));
git_repository_free(_repo);
/* Open a bare repo with a relative path escaping out of the current working directory */
cl_git_pass(git_repository_open(&_repo, "../d/e.git"));
cl_git_pass(chdir(git_buf_cstr(&path_current_workdir)));
git_buf_dispose(&path_current_workdir);
git_buf_dispose(&path_repository);
cleanup_repository("a");
}
void test_repo_init__reinit_bare_repo(void)
{
cl_set_cleanup(&cleanup_repository, "reinit.git");
/* Initialize the repository */
cl_git_pass(git_repository_init(&_repo, "reinit.git", 1));
git_repository_free(_repo);
/* Reinitialize the repository */
cl_git_pass(git_repository_init(&_repo, "reinit.git", 1));
}
void test_repo_init__reinit_too_recent_bare_repo(void)
{
git_config *config;
/* Initialize the repository */
cl_git_pass(git_repository_init(&_repo, "reinit.git", 1));
git_repository_config(&config, _repo);
/*
* Hack the config of the repository to make it look like it has
* been created by a recenter version of git/libgit2
*/
cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 42));
git_config_free(config);
git_repository_free(_repo);
/* Try to reinitialize the repository */
cl_git_fail(git_repository_init(&_repo, "reinit.git", 1));
cl_fixture_cleanup("reinit.git");
}
void test_repo_init__additional_templates(void)
{
git_buf path = GIT_BUF_INIT;
cl_set_cleanup(&cleanup_repository, "tester");
ensure_repository_init("tester", 0, "tester/.git/", "tester/");
cl_git_pass(
git_buf_joinpath(&path, git_repository_path(_repo), "description"));
cl_assert(git_path_isfile(git_buf_cstr(&path)));
cl_git_pass(
git_buf_joinpath(&path, git_repository_path(_repo), "info/exclude"));
cl_assert(git_path_isfile(git_buf_cstr(&path)));
cl_git_pass(
git_buf_joinpath(&path, git_repository_path(_repo), "hooks"));
cl_assert(git_path_isdir(git_buf_cstr(&path)));
/* won't confirm specific contents of hooks dir since it may vary */
git_buf_dispose(&path);
}
static void assert_config_entry_on_init_bytype(
const char *config_key, int expected_value, bool is_bare)
{
git_config *config;
int error, current_value;
const char *repo_path = is_bare ?
"config_entry/test.bare.git" : "config_entry/test.non.bare.git";
cl_set_cleanup(&cleanup_repository, "config_entry");
cl_git_pass(git_repository_init(&_repo, repo_path, is_bare));
cl_git_pass(git_repository_config(&config, _repo));
error = git_config_get_bool(&current_value, config, config_key);
git_config_free(config);
if (expected_value >= 0) {
cl_assert_equal_i(0, error);
cl_assert_equal_i(expected_value, current_value);
} else {
cl_assert_equal_i(expected_value, error);
}
}
static void assert_config_entry_on_init(
const char *config_key, int expected_value)
{
assert_config_entry_on_init_bytype(config_key, expected_value, true);
git_repository_free(_repo);
assert_config_entry_on_init_bytype(config_key, expected_value, false);
}
void test_repo_init__detect_filemode(void)
{
assert_config_entry_on_init("core.filemode", cl_is_chmod_supported());
}
void test_repo_init__detect_ignorecase(void)
{
struct stat st;
bool found_without_match;
cl_git_write2file("testCAPS", "whatever\n", 0, O_CREAT | O_WRONLY, 0666);
found_without_match = (p_stat("Testcaps", &st) == 0);
cl_must_pass(p_unlink("testCAPS"));
assert_config_entry_on_init(
"core.ignorecase", found_without_match ? true : GIT_ENOTFOUND);
}
/*
* Windows: if the filesystem supports symlinks (because we're running
* as administrator, or because the user has opted into it for normal
* users) then we can also opt-in explicitly by settings `core.symlinks`
* in the global config. Symlinks remain off by default.
*/
void test_repo_init__symlinks_win32_enabled_by_global_config(void)
{
#ifndef GIT_WIN32
cl_skip();
#else
git_config *config, *repo_config;
int val;
if (!git_path_supports_symlinks("link"))
cl_skip();
create_tmp_global_config("tmp_global_config", "core.symlinks", "true");
/*
* Create a new repository (can't use `assert_config_on_init` since we
* want to examine configuration levels with more granularity.)
*/
cl_git_pass(git_repository_init(&_repo, "config_entry/test.non.bare.git", false));
/* Ensure that core.symlinks remains set (via the global config). */
cl_git_pass(git_repository_config(&config, _repo));
cl_git_pass(git_config_get_bool(&val, config, "core.symlinks"));
cl_assert_equal_i(1, val);
/*
* Ensure that the repository config does not set core.symlinks.
* It should remain inherited.
*/
cl_git_pass(git_config_open_level(&repo_config, config, GIT_CONFIG_LEVEL_LOCAL));
cl_git_fail_with(GIT_ENOTFOUND, git_config_get_bool(&val, repo_config, "core.symlinks"));
git_config_free(repo_config);
git_config_free(config);
#endif
}
void test_repo_init__symlinks_win32_off_by_default(void)
{
#ifndef GIT_WIN32
cl_skip();
#else
assert_config_entry_on_init("core.symlinks", false);
#endif
}
void test_repo_init__symlinks_posix_detected(void)
{
#ifdef GIT_WIN32
cl_skip();
#else
assert_config_entry_on_init(
"core.symlinks", git_path_supports_symlinks("link") ? GIT_ENOTFOUND : false);
#endif
}
void test_repo_init__detect_precompose_unicode_required(void)
{
#ifdef GIT_USE_ICONV
char *composed = "ḱṷṓn", *decomposed = "ḱṷṓn";
struct stat st;
bool found_with_nfd;
cl_git_write2file(composed, "whatever\n", 0, O_CREAT | O_WRONLY, 0666);
found_with_nfd = (p_stat(decomposed, &st) == 0);
cl_must_pass(p_unlink(composed));
assert_config_entry_on_init("core.precomposeunicode", found_with_nfd);
#else
assert_config_entry_on_init("core.precomposeunicode", GIT_ENOTFOUND);
#endif
}
void test_repo_init__reinit_doesnot_overwrite_ignorecase(void)
{
git_config *config;
int current_value;
/* Init a new repo */
cl_set_cleanup(&cleanup_repository, "not.overwrite.git");
cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1));
/* Change the "core.ignorecase" config value to something unlikely */
git_repository_config(&config, _repo);
git_config_set_int32(config, "core.ignorecase", 42);
git_config_free(config);
git_repository_free(_repo);
_repo = NULL;
/* Reinit the repository */
cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1));
git_repository_config(&config, _repo);
/* Ensure the "core.ignorecase" config value hasn't been updated */
cl_git_pass(git_config_get_int32(&current_value, config, "core.ignorecase"));
cl_assert_equal_i(42, current_value);
git_config_free(config);
}
void test_repo_init__reinit_overwrites_filemode(void)
{
int expected = cl_is_chmod_supported(), current_value;
/* Init a new repo */
cl_set_cleanup(&cleanup_repository, "overwrite.git");
cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1));
/* Change the "core.filemode" config value to something unlikely */
cl_repo_set_bool(_repo, "core.filemode", !expected);
git_repository_free(_repo);
_repo = NULL;
/* Reinit the repository */
cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1));
/* Ensure the "core.filemode" config value has been reset */
current_value = cl_repo_get_bool(_repo, "core.filemode");
cl_assert_equal_i(expected, current_value);
}
void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void)
{
assert_config_entry_on_init_bytype("core.logallrefupdates", GIT_ENOTFOUND, true);
git_repository_free(_repo);
assert_config_entry_on_init_bytype("core.logallrefupdates", true, false);
}
void test_repo_init__extended_0(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
/* without MKDIR this should fail */
cl_git_fail(git_repository_init_ext(&_repo, "extended", &opts));
/* make the directory first, then it should succeed */
cl_git_pass(git_futils_mkdir("extended", 0775, 0));
cl_git_pass(git_repository_init_ext(&_repo, "extended", &opts));
cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/extended/"));
cl_assert(!git__suffixcmp(git_repository_path(_repo), "/extended/.git/"));
cl_assert(!git_repository_is_bare(_repo));
cl_assert(git_repository_is_empty(_repo));
cleanup_repository("extended");
}
void test_repo_init__extended_1(void)
{
git_reference *ref;
git_remote *remote;
struct stat st;
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
opts.flags = GIT_REPOSITORY_INIT_MKPATH |
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP;
opts.workdir_path = "../c_wd";
opts.description = "Awesomest test repository evah";
opts.initial_head = "development";
opts.origin_url = "https://github.com/libgit2/libgit2.git";
cl_git_pass(git_repository_init_ext(&_repo, "root/b/c.git", &opts));
cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/c_wd/"));
cl_assert(!git__suffixcmp(git_repository_path(_repo), "/c.git/"));
cl_assert(git_path_isfile("root/b/c_wd/.git"));
cl_assert(!git_repository_is_bare(_repo));
/* repo will not be counted as empty because we set head to "development" */
cl_assert(!git_repository_is_empty(_repo));
cl_git_pass(git_path_lstat(git_repository_path(_repo), &st));
cl_assert(S_ISDIR(st.st_mode));
if (cl_is_chmod_supported())
cl_assert((S_ISGID & st.st_mode) == S_ISGID);
else
cl_assert((S_ISGID & st.st_mode) == 0);
cl_git_pass(git_reference_lookup(&ref, _repo, "HEAD"));
cl_assert(git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC);
cl_assert_equal_s("refs/heads/development", git_reference_symbolic_target(ref));
git_reference_free(ref);
cl_git_pass(git_remote_lookup(&remote, _repo, "origin"));
cl_assert_equal_s("origin", git_remote_name(remote));
cl_assert_equal_s(opts.origin_url, git_remote_url(remote));
git_remote_free(remote);
git_repository_free(_repo);
cl_fixture_cleanup("root");
}
void test_repo_init__relative_gitdir(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
git_buf dot_git_content = GIT_BUF_INIT;
opts.workdir_path = "../c_wd";
opts.flags =
GIT_REPOSITORY_INIT_MKPATH |
GIT_REPOSITORY_INIT_RELATIVE_GITLINK |
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
/* make the directory first, then it should succeed */
cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts));
cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/"));
cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/"));
cl_assert(!git_repository_is_bare(_repo));
cl_assert(git_repository_is_empty(_repo));
/* Verify that the gitlink and worktree entries are relative */
/* Verify worktree */
assert_config_entry_value(_repo, "core.worktree", "../c_wd/");
/* Verify gitlink */
cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr);
git_buf_dispose(&dot_git_content);
cleanup_repository("root");
}
void test_repo_init__relative_gitdir_2(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
git_buf dot_git_content = GIT_BUF_INIT;
git_buf full_path = GIT_BUF_INIT;
cl_git_pass(git_path_prettify(&full_path, ".", NULL));
cl_git_pass(git_buf_joinpath(&full_path, full_path.ptr, "root/b/c_wd"));
opts.workdir_path = full_path.ptr;
opts.flags =
GIT_REPOSITORY_INIT_MKPATH |
GIT_REPOSITORY_INIT_RELATIVE_GITLINK |
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
/* make the directory first, then it should succeed */
cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts));
git_buf_dispose(&full_path);
cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/"));
cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/"));
cl_assert(!git_repository_is_bare(_repo));
cl_assert(git_repository_is_empty(_repo));
/* Verify that the gitlink and worktree entries are relative */
/* Verify worktree */
assert_config_entry_value(_repo, "core.worktree", "../c_wd/");
/* Verify gitlink */
cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr);
git_buf_dispose(&dot_git_content);
cleanup_repository("root");
}
void test_repo_init__can_reinit_an_initialized_repository(void)
{
git_repository *reinit;
cl_set_cleanup(&cleanup_repository, "extended");
cl_git_pass(git_futils_mkdir("extended", 0775, 0));
cl_git_pass(git_repository_init(&_repo, "extended", false));
cl_git_pass(git_repository_init(&reinit, "extended", false));
cl_assert_equal_s(git_repository_path(_repo), git_repository_path(reinit));
git_repository_free(reinit);
}
void test_repo_init__init_with_initial_commit(void)
{
git_index *index;
cl_set_cleanup(&cleanup_repository, "committed");
/* Initialize the repository */
cl_git_pass(git_repository_init(&_repo, "committed", 0));
/* Index will be automatically created when requested for a new repo */
cl_git_pass(git_repository_index(&index, _repo));
/* Create a file so we can commit it
*
* If you are writing code outside the test suite, you can create this
* file any way that you like, such as:
* FILE *fp = fopen("committed/file.txt", "w");
* fputs("some stuff\n", fp);
* fclose(fp);
* We like to use the help functions because they do error detection
* in a way that's easily compatible with our test suite.
*/
cl_git_mkfile("committed/file.txt", "some stuff\n");
/* Add file to the index */
cl_git_pass(git_index_add_bypath(index, "file.txt"));
cl_git_pass(git_index_write(index));
/* Intentionally not using cl_repo_commit_from_index here so this code
* can be used as an example of how an initial commit is typically
* made to a repository...
*/
/* Make sure we're ready to use git_signature_default :-) */
{
git_config *cfg, *local;
cl_git_pass(git_repository_config(&cfg, _repo));
cl_git_pass(git_config_open_level(&local, cfg, GIT_CONFIG_LEVEL_LOCAL));
cl_git_pass(git_config_set_string(local, "user.name", "Test User"));
cl_git_pass(git_config_set_string(local, "user.email", "t@example.com"));
git_config_free(local);
git_config_free(cfg);
}
/* Create a commit with the new contents of the index */
{
git_signature *sig;
git_oid tree_id, commit_id;
git_tree *tree;
cl_git_pass(git_signature_default(&sig, _repo));
cl_git_pass(git_index_write_tree(&tree_id, index));
cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id));
cl_git_pass(git_commit_create_v(
&commit_id, _repo, "HEAD", sig, sig,
NULL, "First", tree, 0));
git_tree_free(tree);
git_signature_free(sig);
}
git_index_free(index);
}
void test_repo_init__at_filesystem_root(void)
{
git_repository *repo;
const char *sandbox = clar_sandbox_path();
git_buf root = GIT_BUF_INIT;
int root_len;
if (!cl_is_env_set("GITTEST_INVASIVE_FS_STRUCTURE"))
cl_skip();
root_len = git_path_root(sandbox);
cl_assert(root_len >= 0);
git_buf_put(&root, sandbox, root_len+1);
git_buf_joinpath(&root, root.ptr, "libgit2_test_dir");
cl_assert(!git_path_exists(root.ptr));
cl_git_pass(git_repository_init(&repo, root.ptr, 0));
cl_assert(git_path_isdir(root.ptr));
cl_git_pass(git_futils_rmdir_r(root.ptr, NULL, GIT_RMDIR_REMOVE_FILES));
git_buf_dispose(&root);
git_repository_free(repo);
}
void test_repo_init__nonexisting_directory(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
git_repository *repo;
/*
* If creating a repo with non-existing parent directories, then libgit2
* will by default create the complete directory hierarchy if using
* `git_repository_init`. Thus, let's use the extended version and not
* set the `GIT_REPOSITORY_INIT_MKPATH` flag.
*/
cl_git_fail(git_repository_init_ext(&repo, "nonexisting/path", &opts));
}
void test_repo_init__nonexisting_root(void)
{
#ifdef GIT_WIN32
git_repository *repo;
/*
* This really only depends on the nonexistence of the Q: drive. We
* cannot implement the equivalent test on Unix systems, as there is
* fundamentally no path that is disconnected from the root directory.
*/
cl_git_fail(git_repository_init(&repo, "Q:/non/existent/path", 0));
cl_git_fail(git_repository_init(&repo, "Q:\\non\\existent\\path", 0));
#else
clar__skip();
#endif
}
void test_repo_init__unwriteable_directory(void)
{
#ifndef GIT_WIN32
git_repository *repo;
if (geteuid() == 0)
clar__skip();
/*
* Create a non-writeable directory so that we cannot create directories
* inside of it. The root user has CAP_DAC_OVERRIDE, so he doesn't care
* for the directory permissions and thus we need to skip the test if
* run as root user.
*/
cl_must_pass(p_mkdir("unwriteable", 0444));
cl_git_fail(git_repository_init(&repo, "unwriteable/repo", 0));
cl_must_pass(p_rmdir("unwriteable"));
#else
clar__skip();
#endif
}
+39
View File
@@ -0,0 +1,39 @@
#include "clar_libgit2.h"
#include "buffer.h"
#include "refs.h"
#include "posix.h"
static git_repository *_repo;
void test_repo_message__initialize(void)
{
_repo = cl_git_sandbox_init("testrepo.git");
}
void test_repo_message__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_repo_message__none(void)
{
git_buf actual = GIT_BUF_INIT;
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(&actual, _repo));
}
void test_repo_message__message(void)
{
git_buf path = GIT_BUF_INIT, actual = GIT_BUF_INIT;
const char expected[] = "Test\n\nThis is a test of the emergency broadcast system\n";
cl_git_pass(git_buf_joinpath(&path, git_repository_path(_repo), "MERGE_MSG"));
cl_git_mkfile(git_buf_cstr(&path), expected);
cl_git_pass(git_repository_message(&actual, _repo));
cl_assert_equal_s(expected, git_buf_cstr(&actual));
git_buf_dispose(&actual);
cl_git_pass(p_unlink(git_buf_cstr(&path)));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(&actual, _repo));
git_buf_dispose(&path);
}
+27
View File
@@ -0,0 +1,27 @@
#include "clar_libgit2.h"
#include "git2/sys/repository.h"
void test_repo_new__has_nothing(void)
{
git_repository *repo;
cl_git_pass(git_repository_new(&repo));
cl_assert_equal_b(true, git_repository_is_bare(repo));
cl_assert_equal_p(NULL, git_repository_path(repo));
cl_assert_equal_p(NULL, git_repository_workdir(repo));
git_repository_free(repo);
}
void test_repo_new__is_bare_until_workdir_set(void)
{
git_repository *repo;
cl_git_pass(git_repository_new(&repo));
cl_assert_equal_b(true, git_repository_is_bare(repo));
cl_git_pass(git_repository_set_workdir(repo, clar_sandbox_path(), 0));
cl_assert_equal_b(false, git_repository_is_bare(repo));
git_repository_free(repo);
}
+449
View File
@@ -0,0 +1,449 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "sysdir.h"
#include <ctype.h>
void test_repo_open__cleanup(void)
{
cl_git_sandbox_cleanup();
if (git_path_isdir("alternate"))
git_futils_rmdir_r("alternate", NULL, GIT_RMDIR_REMOVE_FILES);
}
void test_repo_open__bare_empty_repo(void)
{
git_repository *repo = cl_git_sandbox_init("empty_bare.git");
cl_assert(git_repository_path(repo) != NULL);
cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
cl_assert(git_repository_workdir(repo) == NULL);
}
void test_repo_open__format_version_1(void)
{
git_repository *repo;
git_config *config;
repo = cl_git_sandbox_init("empty_bare.git");
cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
cl_git_pass(git_repository_config(&config, repo));
cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
git_config_free(config);
git_repository_free(repo);
cl_git_fail(git_repository_open(&repo, "empty_bare.git"));
}
void test_repo_open__standard_empty_repo_through_gitdir(void)
{
git_repository *repo;
cl_git_pass(git_repository_open(&repo, cl_fixture("empty_standard_repo/.gitted")));
cl_assert(git_repository_path(repo) != NULL);
cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
cl_assert(git_repository_workdir(repo) != NULL);
cl_assert(git__suffixcmp(git_repository_workdir(repo), "/") == 0);
git_repository_free(repo);
}
void test_repo_open__standard_empty_repo_through_workdir(void)
{
git_repository *repo = cl_git_sandbox_init("empty_standard_repo");
cl_assert(git_repository_path(repo) != NULL);
cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
cl_assert(git_repository_workdir(repo) != NULL);
cl_assert(git__suffixcmp(git_repository_workdir(repo), "/") == 0);
}
void test_repo_open__open_with_discover(void)
{
static const char *variants[] = {
"attr", "attr/", "attr/.git", "attr/.git/",
"attr/sub", "attr/sub/", "attr/sub/sub", "attr/sub/sub/",
NULL
};
git_repository *repo;
const char **scan;
cl_fixture_sandbox("attr");
cl_git_pass(p_rename("attr/.gitted", "attr/.git"));
for (scan = variants; *scan != NULL; scan++) {
cl_git_pass(git_repository_open_ext(&repo, *scan, 0, NULL));
cl_assert(git__suffixcmp(git_repository_path(repo), "attr/.git/") == 0);
cl_assert(git__suffixcmp(git_repository_workdir(repo), "attr/") == 0);
git_repository_free(repo);
}
cl_fixture_cleanup("attr");
}
void test_repo_open__check_if_repository(void)
{
cl_git_sandbox_init("empty_standard_repo");
/* Pass NULL for the output parameter to check for but not open the repo */
cl_git_pass(git_repository_open_ext(NULL, "empty_standard_repo", 0, NULL));
cl_git_fail(git_repository_open_ext(NULL, "repo_does_not_exist", 0, NULL));
cl_fixture_cleanup("empty_standard_repo");
}
static void make_gitlink_dir(const char *dir, const char *linktext)
{
git_buf path = GIT_BUF_INIT;
cl_git_pass(git_futils_mkdir(dir, 0777, GIT_MKDIR_VERIFY_DIR));
cl_git_pass(git_buf_joinpath(&path, dir, ".git"));
cl_git_rewritefile(path.ptr, linktext);
git_buf_dispose(&path);
}
void test_repo_open__gitlinked(void)
{
/* need to have both repo dir and workdir set up correctly */
git_repository *repo = cl_git_sandbox_init("empty_standard_repo");
git_repository *repo2;
make_gitlink_dir("alternate", "gitdir: ../empty_standard_repo/.git");
cl_git_pass(git_repository_open(&repo2, "alternate"));
cl_assert(git_repository_path(repo2) != NULL);
cl_assert_(git__suffixcmp(git_repository_path(repo2), "empty_standard_repo/.git/") == 0, git_repository_path(repo2));
cl_assert_equal_s(git_repository_path(repo), git_repository_path(repo2));
cl_assert(git_repository_workdir(repo2) != NULL);
cl_assert_(git__suffixcmp(git_repository_workdir(repo2), "alternate/") == 0, git_repository_workdir(repo2));
git_repository_free(repo2);
}
void test_repo_open__with_symlinked_config(void)
{
#ifndef GIT_WIN32
git_buf path = GIT_BUF_INIT;
git_repository *repo;
git_config *cfg;
int32_t value;
cl_git_sandbox_init("empty_standard_repo");
/* Setup .gitconfig as symlink */
cl_git_pass(git_futils_mkdir_r("home", 0777));
cl_git_mkfile("home/.gitconfig.linked", "[global]\ntest = 4567\n");
cl_must_pass(symlink(".gitconfig.linked", "home/.gitconfig"));
cl_git_pass(git_path_prettify(&path, "home", NULL));
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
cl_git_pass(git_config_open_default(&cfg));
cl_git_pass(git_config_get_int32(&value, cfg, "global.test"));
cl_assert_equal_i(4567, value);
git_config_free(cfg);
git_repository_free(repo);
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
cl_sandbox_set_search_path_defaults();
git_buf_dispose(&path);
#endif
}
void test_repo_open__from_git_new_workdir(void)
{
#ifndef GIT_WIN32
/* The git-new-workdir script that ships with git sets up a bunch of
* symlinks to create a second workdir that shares the object db with
* another checkout. Libgit2 can open a repo that has been configured
* this way.
*/
git_repository *repo2;
git_buf link_tgt = GIT_BUF_INIT, link = GIT_BUF_INIT, body = GIT_BUF_INIT;
const char **scan;
int link_fd;
static const char *links[] = {
"config", "refs", "logs/refs", "objects", "info", "hooks",
"packed-refs", "remotes", "rr-cache", "svn", NULL
};
static const char *copies[] = {
"HEAD", NULL
};
cl_git_sandbox_init("empty_standard_repo");
cl_git_pass(p_mkdir("alternate", 0777));
cl_git_pass(p_mkdir("alternate/.git", 0777));
for (scan = links; *scan != NULL; scan++) {
git_buf_joinpath(&link_tgt, "empty_standard_repo/.git", *scan);
if (git_path_exists(link_tgt.ptr)) {
git_buf_joinpath(&link_tgt, "../../empty_standard_repo/.git", *scan);
git_buf_joinpath(&link, "alternate/.git", *scan);
if (strchr(*scan, '/'))
git_futils_mkpath2file(link.ptr, 0777);
cl_assert_(symlink(link_tgt.ptr, link.ptr) == 0, strerror(errno));
}
}
for (scan = copies; *scan != NULL; scan++) {
git_buf_joinpath(&link_tgt, "empty_standard_repo/.git", *scan);
if (git_path_exists(link_tgt.ptr)) {
git_buf_joinpath(&link, "alternate/.git", *scan);
cl_git_pass(git_futils_readbuffer(&body, link_tgt.ptr));
cl_assert((link_fd = git_futils_creat_withpath(link.ptr, 0777, 0666)) >= 0);
cl_must_pass(p_write(link_fd, body.ptr, body.size));
p_close(link_fd);
}
}
git_buf_dispose(&link_tgt);
git_buf_dispose(&link);
git_buf_dispose(&body);
cl_git_pass(git_repository_open(&repo2, "alternate"));
cl_assert(git_repository_path(repo2) != NULL);
cl_assert_(git__suffixcmp(git_repository_path(repo2), "alternate/.git/") == 0, git_repository_path(repo2));
cl_assert(git_repository_workdir(repo2) != NULL);
cl_assert_(git__suffixcmp(git_repository_workdir(repo2), "alternate/") == 0, git_repository_workdir(repo2));
git_repository_free(repo2);
#else
cl_skip();
#endif
}
void test_repo_open__failures(void)
{
git_repository *base, *repo;
git_buf ceiling = GIT_BUF_INIT;
base = cl_git_sandbox_init("attr");
cl_git_pass(git_buf_sets(&ceiling, git_repository_workdir(base)));
/* fail with no searching */
cl_git_fail(git_repository_open(&repo, "attr/sub"));
cl_git_fail(git_repository_open_ext(
&repo, "attr/sub", GIT_REPOSITORY_OPEN_NO_SEARCH, NULL));
/* fail with ceiling too low */
cl_git_fail(git_repository_open_ext(&repo, "attr/sub", 0, ceiling.ptr));
cl_git_pass(git_buf_joinpath(&ceiling, ceiling.ptr, "sub"));
cl_git_fail(git_repository_open_ext(&repo, "attr/sub/sub", 0, ceiling.ptr));
/* fail with no repo */
cl_git_pass(p_mkdir("alternate", 0777));
cl_git_pass(p_mkdir("alternate/.git", 0777));
cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL));
cl_git_fail(git_repository_open_ext(&repo, "alternate/.git", 0, NULL));
/* fail with no searching and no appending .git */
cl_git_fail(git_repository_open_ext(
&repo, "attr",
GIT_REPOSITORY_OPEN_NO_SEARCH | GIT_REPOSITORY_OPEN_NO_DOTGIT,
NULL));
git_buf_dispose(&ceiling);
}
void test_repo_open__bad_gitlinks(void)
{
git_repository *repo;
static const char *bad_links[] = {
"garbage\n", "gitdir", "gitdir:\n", "gitdir: foobar",
"gitdir: ../invalid", "gitdir: ../invalid2",
"gitdir: ../attr/.git with extra stuff",
NULL
};
const char **scan;
cl_git_sandbox_init("attr");
cl_git_pass(p_mkdir("invalid", 0777));
cl_git_pass(git_futils_mkdir_r("invalid2/.git", 0777));
for (scan = bad_links; *scan != NULL; scan++) {
make_gitlink_dir("alternate", *scan);
cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL));
}
git_futils_rmdir_r("invalid", NULL, GIT_RMDIR_REMOVE_FILES);
git_futils_rmdir_r("invalid2", NULL, GIT_RMDIR_REMOVE_FILES);
}
#ifdef GIT_WIN32
static void unposix_path(git_buf *path)
{
char *src, *tgt;
src = tgt = path->ptr;
/* convert "/d/..." to "d:\..." */
if (src[0] == '/' && isalpha(src[1]) && src[2] == '/') {
*tgt++ = src[1];
*tgt++ = ':';
*tgt++ = '\\';
src += 3;
}
while (*src) {
*tgt++ = (*src == '/') ? '\\' : *src;
src++;
}
*tgt = '\0';
}
#endif
void test_repo_open__win32_path(void)
{
#ifdef GIT_WIN32
git_repository *repo = cl_git_sandbox_init("empty_standard_repo"), *repo2;
git_buf winpath = GIT_BUF_INIT;
static const char *repo_path = "empty_standard_repo/.git/";
static const char *repo_wd = "empty_standard_repo/";
cl_assert(git__suffixcmp(git_repository_path(repo), repo_path) == 0);
cl_assert(git__suffixcmp(git_repository_workdir(repo), repo_wd) == 0);
cl_git_pass(git_buf_sets(&winpath, git_repository_path(repo)));
unposix_path(&winpath);
cl_git_pass(git_repository_open(&repo2, winpath.ptr));
cl_assert(git__suffixcmp(git_repository_path(repo2), repo_path) == 0);
cl_assert(git__suffixcmp(git_repository_workdir(repo2), repo_wd) == 0);
git_repository_free(repo2);
cl_git_pass(git_buf_sets(&winpath, git_repository_path(repo)));
git_buf_truncate(&winpath, winpath.size - 1); /* remove trailing '/' */
unposix_path(&winpath);
cl_git_pass(git_repository_open(&repo2, winpath.ptr));
cl_assert(git__suffixcmp(git_repository_path(repo2), repo_path) == 0);
cl_assert(git__suffixcmp(git_repository_workdir(repo2), repo_wd) == 0);
git_repository_free(repo2);
cl_git_pass(git_buf_sets(&winpath, git_repository_workdir(repo)));
unposix_path(&winpath);
cl_git_pass(git_repository_open(&repo2, winpath.ptr));
cl_assert(git__suffixcmp(git_repository_path(repo2), repo_path) == 0);
cl_assert(git__suffixcmp(git_repository_workdir(repo2), repo_wd) == 0);
git_repository_free(repo2);
cl_git_pass(git_buf_sets(&winpath, git_repository_workdir(repo)));
git_buf_truncate(&winpath, winpath.size - 1); /* remove trailing '/' */
unposix_path(&winpath);
cl_git_pass(git_repository_open(&repo2, winpath.ptr));
cl_assert(git__suffixcmp(git_repository_path(repo2), repo_path) == 0);
cl_assert(git__suffixcmp(git_repository_workdir(repo2), repo_wd) == 0);
git_repository_free(repo2);
git_buf_dispose(&winpath);
#endif
}
void test_repo_open__opening_a_non_existing_repository_returns_ENOTFOUND(void)
{
git_repository *repo;
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_open(&repo, "i-do-not/exist"));
}
void test_repo_open__no_config(void)
{
git_buf path = GIT_BUF_INIT;
git_repository *repo;
git_config *config;
cl_fixture_sandbox("empty_standard_repo");
cl_git_pass(cl_rename(
"empty_standard_repo/.gitted", "empty_standard_repo/.git"));
/* remove local config */
cl_git_pass(git_futils_rmdir_r(
"empty_standard_repo/.git/config", NULL, GIT_RMDIR_REMOVE_FILES));
/* isolate from system level configs */
cl_must_pass(p_mkdir("alternate", 0777));
cl_git_pass(git_path_prettify(&path, "alternate", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
git_buf_dispose(&path);
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
cl_git_pass(git_repository_config(&config, repo));
cl_git_pass(git_config_set_string(config, "test.set", "42"));
git_config_free(config);
git_repository_free(repo);
cl_fixture_cleanup("empty_standard_repo");
cl_sandbox_set_search_path_defaults();
}
void test_repo_open__force_bare(void)
{
/* need to have both repo dir and workdir set up correctly */
git_repository *repo = cl_git_sandbox_init("empty_standard_repo");
git_repository *barerepo;
make_gitlink_dir("alternate", "gitdir: ../empty_standard_repo/.git");
cl_assert(!git_repository_is_bare(repo));
cl_git_pass(git_repository_open(&barerepo, "alternate"));
cl_assert(!git_repository_is_bare(barerepo));
git_repository_free(barerepo);
cl_git_pass(git_repository_open_bare(
&barerepo, "empty_standard_repo/.git"));
cl_assert(git_repository_is_bare(barerepo));
git_repository_free(barerepo);
cl_git_fail(git_repository_open_bare(&barerepo, "alternate/.git"));
cl_git_pass(git_repository_open_ext(
&barerepo, "alternate/.git", GIT_REPOSITORY_OPEN_BARE, NULL));
cl_assert(git_repository_is_bare(barerepo));
git_repository_free(barerepo);
cl_git_pass(p_mkdir("empty_standard_repo/subdir", 0777));
cl_git_mkfile("empty_standard_repo/subdir/something.txt", "something");
cl_git_fail(git_repository_open_bare(
&barerepo, "empty_standard_repo/subdir"));
cl_git_pass(git_repository_open_ext(
&barerepo, "empty_standard_repo/subdir", GIT_REPOSITORY_OPEN_BARE, NULL));
cl_assert(git_repository_is_bare(barerepo));
git_repository_free(barerepo);
cl_git_pass(p_mkdir("alternate/subdir", 0777));
cl_git_pass(p_mkdir("alternate/subdir/sub2", 0777));
cl_git_mkfile("alternate/subdir/sub2/something.txt", "something");
cl_git_fail(git_repository_open_bare(&barerepo, "alternate/subdir/sub2"));
cl_git_pass(git_repository_open_ext(
&barerepo, "alternate/subdir/sub2",
GIT_REPOSITORY_OPEN_BARE|GIT_REPOSITORY_OPEN_CROSS_FS, NULL));
cl_assert(git_repository_is_bare(barerepo));
git_repository_free(barerepo);
}
+385
View File
@@ -0,0 +1,385 @@
#include "clar_libgit2.h"
#include "git2/pathspec.h"
static git_repository *g_repo;
void test_repo_pathspec__initialize(void)
{
g_repo = cl_git_sandbox_init("status");
}
void test_repo_pathspec__cleanup(void)
{
cl_git_sandbox_cleanup();
g_repo = NULL;
}
static char *str0[] = { "*_file", "new_file", "garbage" };
static char *str1[] = { "*_FILE", "NEW_FILE", "GARBAGE" };
static char *str2[] = { "staged_*" };
static char *str3[] = { "!subdir", "*_file", "new_file" };
static char *str4[] = { "*" };
static char *str5[] = { "S*" };
void test_repo_pathspec__workdir0(void)
{
git_strarray s;
git_pathspec *ps;
git_pathspec_match_list *m;
/* { "*_file", "new_file", "garbage" } */
s.strings = str0; s.count = ARRAY_SIZE(str0);
cl_git_pass(git_pathspec_new(&ps, &s));
cl_git_pass(git_pathspec_match_workdir(&m, g_repo, 0, ps));
cl_assert_equal_sz(10, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(0, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(10, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(1, git_pathspec_match_list_failed_entrycount(m));
cl_assert_equal_s("garbage", git_pathspec_match_list_failed_entry(m, 0));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_FIND_FAILURES | GIT_PATHSPEC_FAILURES_ONLY, ps));
cl_assert_equal_sz(0, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(1, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
git_pathspec_free(ps);
}
void test_repo_pathspec__workdir1(void)
{
git_strarray s;
git_pathspec *ps;
git_pathspec_match_list *m;
/* { "*_FILE", "NEW_FILE", "GARBAGE" } */
s.strings = str1; s.count = ARRAY_SIZE(str1);
cl_git_pass(git_pathspec_new(&ps, &s));
cl_git_pass(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_IGNORE_CASE, ps));
cl_assert_equal_sz(10, git_pathspec_match_list_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_USE_CASE, ps));
cl_assert_equal_sz(0, git_pathspec_match_list_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_fail(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_USE_CASE | GIT_PATHSPEC_NO_MATCH_ERROR, ps));
cl_git_pass(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_IGNORE_CASE | GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(10, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(1, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_USE_CASE | GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(0, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(3, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
git_pathspec_free(ps);
}
void test_repo_pathspec__workdir2(void)
{
git_strarray s;
git_pathspec *ps;
git_pathspec_match_list *m;
/* { "staged_*" } */
s.strings = str2; s.count = ARRAY_SIZE(str2);
cl_git_pass(git_pathspec_new(&ps, &s));
cl_git_pass(git_pathspec_match_workdir(&m, g_repo, 0, ps));
cl_assert_equal_sz(5, git_pathspec_match_list_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(5, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(0, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_fail(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_NO_GLOB | GIT_PATHSPEC_NO_MATCH_ERROR, ps));
cl_git_pass(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_NO_GLOB | GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(0, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(1, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
git_pathspec_free(ps);
}
void test_repo_pathspec__workdir3(void)
{
git_strarray s;
git_pathspec *ps;
git_pathspec_match_list *m;
/* { "!subdir", "*_file", "new_file" } */
s.strings = str3; s.count = ARRAY_SIZE(str3);
cl_git_pass(git_pathspec_new(&ps, &s));
cl_git_pass(git_pathspec_match_workdir(&m, g_repo, 0, ps));
cl_assert_equal_sz(7, git_pathspec_match_list_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_workdir(&m, g_repo,
GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(7, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(0, git_pathspec_match_list_failed_entrycount(m));
cl_assert_equal_s("current_file", git_pathspec_match_list_entry(m, 0));
cl_assert_equal_s("modified_file", git_pathspec_match_list_entry(m, 1));
cl_assert_equal_s("new_file", git_pathspec_match_list_entry(m, 2));
cl_assert_equal_s("staged_changes_modified_file", git_pathspec_match_list_entry(m, 3));
cl_assert_equal_s("staged_delete_modified_file", git_pathspec_match_list_entry(m, 4));
cl_assert_equal_s("staged_new_file", git_pathspec_match_list_entry(m, 5));
cl_assert_equal_s("staged_new_file_modified_file", git_pathspec_match_list_entry(m, 6));
cl_assert_equal_s(NULL, git_pathspec_match_list_entry(m, 7));
git_pathspec_match_list_free(m);
git_pathspec_free(ps);
}
void test_repo_pathspec__workdir4(void)
{
git_strarray s;
git_pathspec *ps;
git_pathspec_match_list *m;
/* { "*" } */
s.strings = str4; s.count = ARRAY_SIZE(str4);
cl_git_pass(git_pathspec_new(&ps, &s));
cl_git_pass(git_pathspec_match_workdir(&m, g_repo, 0, ps));
cl_assert_equal_sz(13, git_pathspec_match_list_entrycount(m));
cl_assert_equal_s("\xE8\xBF\x99", git_pathspec_match_list_entry(m, 12));
git_pathspec_match_list_free(m);
git_pathspec_free(ps);
}
void test_repo_pathspec__index0(void)
{
git_index *idx;
git_strarray s;
git_pathspec *ps;
git_pathspec_match_list *m;
cl_git_pass(git_repository_index(&idx, g_repo));
/* { "*_file", "new_file", "garbage" } */
s.strings = str0; s.count = ARRAY_SIZE(str0);
cl_git_pass(git_pathspec_new(&ps, &s));
cl_git_pass(git_pathspec_match_index(&m, idx, 0, ps));
cl_assert_equal_sz(9, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(0, git_pathspec_match_list_failed_entrycount(m));
cl_assert_equal_s("current_file", git_pathspec_match_list_entry(m, 0));
cl_assert_equal_s("modified_file", git_pathspec_match_list_entry(m, 1));
cl_assert_equal_s("staged_changes_modified_file", git_pathspec_match_list_entry(m, 2));
cl_assert_equal_s("staged_new_file", git_pathspec_match_list_entry(m, 3));
cl_assert_equal_s("staged_new_file_deleted_file", git_pathspec_match_list_entry(m, 4));
cl_assert_equal_s("staged_new_file_modified_file", git_pathspec_match_list_entry(m, 5));
cl_assert_equal_s("subdir/current_file", git_pathspec_match_list_entry(m, 6));
cl_assert_equal_s("subdir/deleted_file", git_pathspec_match_list_entry(m, 7));
cl_assert_equal_s("subdir/modified_file", git_pathspec_match_list_entry(m, 8));
cl_assert_equal_s(NULL, git_pathspec_match_list_entry(m, 9));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_index(&m, idx,
GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(9, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(2, git_pathspec_match_list_failed_entrycount(m));
cl_assert_equal_s("new_file", git_pathspec_match_list_failed_entry(m, 0));
cl_assert_equal_s("garbage", git_pathspec_match_list_failed_entry(m, 1));
cl_assert_equal_s(NULL, git_pathspec_match_list_failed_entry(m, 2));
git_pathspec_match_list_free(m);
git_pathspec_free(ps);
git_index_free(idx);
}
void test_repo_pathspec__index1(void)
{
/* Currently the USE_CASE and IGNORE_CASE flags don't work on the
* index because the index sort order for the index iterator is
* set by the index itself. I think the correct fix is for the
* index not to embed a global sort order but to support traversal
* in either case sensitive or insensitive order in a stateless
* manner.
*
* Anyhow, as it is, there is no point in doing this test.
*/
#if 0
git_index *idx;
git_strarray s;
git_pathspec *ps;
git_pathspec_match_list *m;
cl_git_pass(git_repository_index(&idx, g_repo));
/* { "*_FILE", "NEW_FILE", "GARBAGE" } */
s.strings = str1; s.count = ARRAY_SIZE(str1);
cl_git_pass(git_pathspec_new(&ps, &s));
cl_git_pass(git_pathspec_match_index(&m, idx,
GIT_PATHSPEC_USE_CASE, ps));
cl_assert_equal_sz(0, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(0, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_index(&m, idx,
GIT_PATHSPEC_USE_CASE | GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(0, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(3, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_index(&m, idx,
GIT_PATHSPEC_IGNORE_CASE | GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(10, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(2, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
git_pathspec_free(ps);
git_index_free(idx);
#endif
}
void test_repo_pathspec__tree0(void)
{
git_object *tree;
git_strarray s;
git_pathspec *ps;
git_pathspec_match_list *m;
/* { "*_file", "new_file", "garbage" } */
s.strings = str0; s.count = ARRAY_SIZE(str0);
cl_git_pass(git_pathspec_new(&ps, &s));
cl_git_pass(git_revparse_single(&tree, g_repo, "HEAD~2^{tree}"));
cl_git_pass(git_pathspec_match_tree(&m, (git_tree *)tree,
GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(4, git_pathspec_match_list_entrycount(m));
cl_assert_equal_s("current_file", git_pathspec_match_list_entry(m, 0));
cl_assert_equal_s("modified_file", git_pathspec_match_list_entry(m, 1));
cl_assert_equal_s("staged_changes_modified_file", git_pathspec_match_list_entry(m, 2));
cl_assert_equal_s("staged_delete_modified_file", git_pathspec_match_list_entry(m, 3));
cl_assert_equal_s(NULL, git_pathspec_match_list_entry(m, 4));
cl_assert_equal_sz(2, git_pathspec_match_list_failed_entrycount(m));
cl_assert_equal_s("new_file", git_pathspec_match_list_failed_entry(m, 0));
cl_assert_equal_s("garbage", git_pathspec_match_list_failed_entry(m, 1));
cl_assert_equal_s(NULL, git_pathspec_match_list_failed_entry(m, 2));
git_pathspec_match_list_free(m);
git_object_free(tree);
cl_git_pass(git_revparse_single(&tree, g_repo, "HEAD^{tree}"));
cl_git_pass(git_pathspec_match_tree(&m, (git_tree *)tree,
GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(7, git_pathspec_match_list_entrycount(m));
cl_assert_equal_s("current_file", git_pathspec_match_list_entry(m, 0));
cl_assert_equal_s("modified_file", git_pathspec_match_list_entry(m, 1));
cl_assert_equal_s("staged_changes_modified_file", git_pathspec_match_list_entry(m, 2));
cl_assert_equal_s("staged_delete_modified_file", git_pathspec_match_list_entry(m, 3));
cl_assert_equal_s("subdir/current_file", git_pathspec_match_list_entry(m, 4));
cl_assert_equal_s("subdir/deleted_file", git_pathspec_match_list_entry(m, 5));
cl_assert_equal_s("subdir/modified_file", git_pathspec_match_list_entry(m, 6));
cl_assert_equal_s(NULL, git_pathspec_match_list_entry(m, 7));
cl_assert_equal_sz(2, git_pathspec_match_list_failed_entrycount(m));
cl_assert_equal_s("new_file", git_pathspec_match_list_failed_entry(m, 0));
cl_assert_equal_s("garbage", git_pathspec_match_list_failed_entry(m, 1));
cl_assert_equal_s(NULL, git_pathspec_match_list_failed_entry(m, 2));
git_pathspec_match_list_free(m);
git_object_free(tree);
git_pathspec_free(ps);
}
void test_repo_pathspec__tree5(void)
{
git_object *tree;
git_strarray s;
git_pathspec *ps;
git_pathspec_match_list *m;
/* { "S*" } */
s.strings = str5; s.count = ARRAY_SIZE(str5);
cl_git_pass(git_pathspec_new(&ps, &s));
cl_git_pass(git_revparse_single(&tree, g_repo, "HEAD~2^{tree}"));
cl_git_pass(git_pathspec_match_tree(&m, (git_tree *)tree,
GIT_PATHSPEC_USE_CASE | GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(0, git_pathspec_match_list_entrycount(m));
cl_assert_equal_sz(1, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
cl_git_pass(git_pathspec_match_tree(&m, (git_tree *)tree,
GIT_PATHSPEC_IGNORE_CASE | GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(5, git_pathspec_match_list_entrycount(m));
cl_assert_equal_s("staged_changes", git_pathspec_match_list_entry(m, 0));
cl_assert_equal_s("staged_delete_modified_file", git_pathspec_match_list_entry(m, 4));
cl_assert_equal_sz(0, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
git_object_free(tree);
cl_git_pass(git_revparse_single(&tree, g_repo, "HEAD^{tree}"));
cl_git_pass(git_pathspec_match_tree(&m, (git_tree *)tree,
GIT_PATHSPEC_IGNORE_CASE | GIT_PATHSPEC_FIND_FAILURES, ps));
cl_assert_equal_sz(9, git_pathspec_match_list_entrycount(m));
cl_assert_equal_s("staged_changes", git_pathspec_match_list_entry(m, 0));
cl_assert_equal_s("subdir.txt", git_pathspec_match_list_entry(m, 5));
cl_assert_equal_s("subdir/current_file", git_pathspec_match_list_entry(m, 6));
cl_assert_equal_sz(0, git_pathspec_match_list_failed_entrycount(m));
git_pathspec_match_list_free(m);
git_object_free(tree);
git_pathspec_free(ps);
}
void test_repo_pathspec__in_memory(void)
{
static char *strings[] = { "one", "two*", "!three*", "*four" };
git_strarray s = { strings, ARRAY_SIZE(strings) };
git_pathspec *ps;
cl_git_pass(git_pathspec_new(&ps, &s));
cl_assert(git_pathspec_matches_path(ps, 0, "one"));
cl_assert(!git_pathspec_matches_path(ps, 0, "ONE"));
cl_assert(git_pathspec_matches_path(ps, GIT_PATHSPEC_IGNORE_CASE, "ONE"));
cl_assert(git_pathspec_matches_path(ps, 0, "two"));
cl_assert(git_pathspec_matches_path(ps, 0, "two.txt"));
cl_assert(!git_pathspec_matches_path(ps, 0, "three.txt"));
cl_assert(git_pathspec_matches_path(ps, 0, "anything.four"));
cl_assert(!git_pathspec_matches_path(ps, 0, "three.four"));
cl_assert(!git_pathspec_matches_path(ps, 0, "nomatch"));
cl_assert(!git_pathspec_matches_path(ps, GIT_PATHSPEC_NO_GLOB, "two"));
cl_assert(git_pathspec_matches_path(ps, GIT_PATHSPEC_NO_GLOB, "two*"));
cl_assert(!git_pathspec_matches_path(ps, GIT_PATHSPEC_NO_GLOB, "anyfour"));
cl_assert(git_pathspec_matches_path(ps, GIT_PATHSPEC_NO_GLOB, "*four"));
git_pathspec_free(ps);
}
+37
View File
@@ -0,0 +1,37 @@
#include "clar_libgit2.h"
#include "refs.h"
#include "repo_helpers.h"
#include "posix.h"
void make_head_unborn(git_repository* repo, const char *target)
{
git_reference *head;
cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, target, 1, NULL));
git_reference_free(head);
}
void delete_head(git_repository* repo)
{
git_buf head_path = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&head_path, git_repository_path(repo), GIT_HEAD_FILE));
cl_git_pass(p_unlink(git_buf_cstr(&head_path)));
git_buf_dispose(&head_path);
}
void create_tmp_global_config(const char *dirname, const char *key, const char *val)
{
git_buf path = GIT_BUF_INIT;
git_config *config;
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH,
GIT_CONFIG_LEVEL_GLOBAL, dirname));
cl_must_pass(p_mkdir(dirname, 0777));
cl_git_pass(git_buf_joinpath(&path, dirname, ".gitconfig"));
cl_git_pass(git_config_open_ondisk(&config, path.ptr));
cl_git_pass(git_config_set_string(config, key, val));
git_config_free(config);
git_buf_dispose(&path);
}
+7
View File
@@ -0,0 +1,7 @@
#include "common.h"
#define NON_EXISTING_HEAD "refs/heads/hide/and/seek"
extern void make_head_unborn(git_repository* repo, const char *target);
extern void delete_head(git_repository* repo);
extern void create_tmp_global_config(const char *path, const char *key, const char *val);
+132
View File
@@ -0,0 +1,132 @@
#include "clar_libgit2.h"
#include "../submodule/submodule_helpers.h"
#include "repository.h"
void test_repo_reservedname__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_repo_reservedname__includes_shortname_on_win32(void)
{
git_repository *repo;
git_buf *reserved;
size_t reserved_len;
repo = cl_git_sandbox_init("nasty");
cl_assert(git_repository__reserved_names(&reserved, &reserved_len, repo, false));
#ifdef GIT_WIN32
cl_assert_equal_i(2, reserved_len);
cl_assert_equal_s(".git", reserved[0].ptr);
cl_assert_equal_s("GIT~1", reserved[1].ptr);
#else
cl_assert_equal_i(1, reserved_len);
cl_assert_equal_s(".git", reserved[0].ptr);
#endif
}
void test_repo_reservedname__includes_shortname_when_requested(void)
{
git_repository *repo;
git_buf *reserved;
size_t reserved_len;
repo = cl_git_sandbox_init("nasty");
cl_assert(git_repository__reserved_names(&reserved, &reserved_len, repo, true));
cl_assert_equal_i(2, reserved_len);
cl_assert_equal_s(".git", reserved[0].ptr);
cl_assert_equal_s("GIT~1", reserved[1].ptr);
}
/* Ensures that custom shortnames are included: creates a GIT~1 so that the
* .git folder itself will have to be named GIT~2
*/
void test_repo_reservedname__custom_shortname_recognized(void)
{
#ifdef GIT_WIN32
git_repository *repo;
git_buf *reserved;
size_t reserved_len;
if (!cl_sandbox_supports_8dot3())
clar__skip();
repo = cl_git_sandbox_init("nasty");
cl_must_pass(p_rename("nasty/.git", "nasty/_temp"));
cl_git_write2file("nasty/git~1", "", 0, O_RDWR|O_CREAT, 0666);
cl_must_pass(p_rename("nasty/_temp", "nasty/.git"));
cl_assert(git_repository__reserved_names(&reserved, &reserved_len, repo, true));
cl_assert_equal_i(3, reserved_len);
cl_assert_equal_s(".git", reserved[0].ptr);
cl_assert_equal_s("GIT~1", reserved[1].ptr);
cl_assert_equal_s("GIT~2", reserved[2].ptr);
#endif
}
/* When looking at the short name for a submodule, we need to prevent
* people from overwriting the `.git` file in the submodule working
* directory itself. We don't want to look at the actual repository
* path, since it will be in the super's repository above us, and
* typically named with the name of our subrepository. Consequently,
* preventing access to the short name of the actual repository path
* would prevent us from creating files with the same name as the
* subrepo. (Eg, a submodule named "libgit2" could not contain a file
* named "libgit2", which would be unfortunate.)
*/
void test_repo_reservedname__submodule_pointer(void)
{
#ifdef GIT_WIN32
git_repository *super_repo, *sub_repo;
git_submodule *sub;
git_buf *sub_reserved;
size_t sub_reserved_len;
if (!cl_sandbox_supports_8dot3())
clar__skip();
super_repo = setup_fixture_submod2();
assert_submodule_exists(super_repo, "sm_unchanged");
cl_git_pass(git_submodule_lookup(&sub, super_repo, "sm_unchanged"));
cl_git_pass(git_submodule_open(&sub_repo, sub));
cl_assert(git_repository__reserved_names(&sub_reserved, &sub_reserved_len, sub_repo, true));
cl_assert_equal_i(2, sub_reserved_len);
cl_assert_equal_s(".git", sub_reserved[0].ptr);
cl_assert_equal_s("GIT~1", sub_reserved[1].ptr);
git_submodule_free(sub);
git_repository_free(sub_repo);
#endif
}
/* Like the `submodule_pointer` test (above), this ensures that we do not
* follow the gitlink to the submodule's repository location and treat that
* as a reserved name. This tests at an initial submodule update, where the
* submodule repo is being created.
*/
void test_repo_reservedname__submodule_pointer_during_create(void)
{
git_repository *repo;
git_submodule *sm;
git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
git_buf url = GIT_BUF_INIT;
repo = setup_fixture_super();
cl_git_pass(git_buf_joinpath(&url, clar_sandbox_path(), "sub.git"));
cl_repo_set_string(repo, "submodule.sub.url", url.ptr);
cl_git_pass(git_submodule_lookup(&sm, repo, "sub"));
cl_git_pass(git_submodule_update(sm, 1, &update_options));
git_submodule_free(sm);
git_buf_dispose(&url);
}
+109
View File
@@ -0,0 +1,109 @@
#include "clar_libgit2.h"
#include "git2/sys/repository.h"
#include "buffer.h"
#include "posix.h"
#include "util.h"
#include "path.h"
#include "futils.h"
static git_repository *repo;
void test_repo_setters__initialize(void)
{
cl_fixture_sandbox("testrepo.git");
cl_git_pass(git_repository_open(&repo, "testrepo.git"));
cl_must_pass(p_mkdir("new_workdir", 0777));
}
void test_repo_setters__cleanup(void)
{
git_repository_free(repo);
repo = NULL;
cl_fixture_cleanup("testrepo.git");
cl_fixture_cleanup("new_workdir");
}
void test_repo_setters__setting_a_workdir_turns_a_bare_repository_into_a_standard_one(void)
{
cl_assert(git_repository_is_bare(repo) == 1);
cl_assert(git_repository_workdir(repo) == NULL);
cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", false));
cl_assert(git_repository_workdir(repo) != NULL);
cl_assert(git_repository_is_bare(repo) == 0);
}
void test_repo_setters__setting_a_workdir_prettifies_its_path(void)
{
cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", false));
cl_assert(git__suffixcmp(git_repository_workdir(repo), "new_workdir/") == 0);
}
void test_repo_setters__setting_a_workdir_creates_a_gitlink(void)
{
git_config *cfg;
git_buf buf = GIT_BUF_INIT;
git_buf content = GIT_BUF_INIT;
cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", true));
cl_assert(git_path_isfile("./new_workdir/.git"));
cl_git_pass(git_futils_readbuffer(&content, "./new_workdir/.git"));
cl_assert(git__prefixcmp(git_buf_cstr(&content), "gitdir: ") == 0);
cl_assert(git__suffixcmp(git_buf_cstr(&content), "testrepo.git/") == 0);
git_buf_dispose(&content);
cl_git_pass(git_repository_config(&cfg, repo));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.worktree"));
cl_assert(git__suffixcmp(git_buf_cstr(&buf), "new_workdir/") == 0);
git_buf_dispose(&buf);
git_config_free(cfg);
}
void test_repo_setters__setting_a_new_index_on_a_repo_which_has_already_loaded_one_properly_honors_the_refcount(void)
{
git_index *new_index;
cl_git_pass(git_index_open(&new_index, "./my-index"));
cl_assert(((git_refcount *)new_index)->refcount.val == 1);
git_repository_set_index(repo, new_index);
cl_assert(((git_refcount *)new_index)->refcount.val == 2);
git_repository_free(repo);
cl_assert(((git_refcount *)new_index)->refcount.val == 1);
git_index_free(new_index);
/*
* Ensure the cleanup method won't try to free the repo as it's already been taken care of
*/
repo = NULL;
}
void test_repo_setters__setting_a_new_odb_on_a_repo_which_already_loaded_one_properly_honors_the_refcount(void)
{
git_odb *new_odb;
cl_git_pass(git_odb_open(&new_odb, "./testrepo.git/objects"));
cl_assert(((git_refcount *)new_odb)->refcount.val == 1);
git_repository_set_odb(repo, new_odb);
cl_assert(((git_refcount *)new_odb)->refcount.val == 2);
git_repository_free(repo);
cl_assert(((git_refcount *)new_odb)->refcount.val == 1);
git_odb_free(new_odb);
/*
* Ensure the cleanup method won't try to free the repo as it's already been taken care of
*/
repo = NULL;
}
+39
View File
@@ -0,0 +1,39 @@
#include "clar_libgit2.h"
#include "futils.h"
static git_repository *g_repo;
void test_repo_shallow__initialize(void)
{
}
void test_repo_shallow__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_repo_shallow__no_shallow_file(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
}
void test_repo_shallow__empty_shallow_file(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_git_mkfile("testrepo.git/shallow", "");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
}
void test_repo_shallow__shallow_repo(void)
{
g_repo = cl_git_sandbox_init("shallow.git");
cl_assert_equal_i(1, git_repository_is_shallow(g_repo));
}
void test_repo_shallow__clears_errors(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
cl_assert_equal_p(NULL, git_error_last());
}
+132
View File
@@ -0,0 +1,132 @@
#include "clar_libgit2.h"
#include "buffer.h"
#include "refs.h"
#include "posix.h"
#include "futils.h"
static git_repository *_repo;
static git_buf _path;
void test_repo_state__initialize(void)
{
_repo = cl_git_sandbox_init("testrepo.git");
}
void test_repo_state__cleanup(void)
{
cl_git_sandbox_cleanup();
git_buf_dispose(&_path);
}
static void setup_simple_state(const char *filename)
{
cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), filename));
git_futils_mkpath2file(git_buf_cstr(&_path), 0777);
cl_git_mkfile(git_buf_cstr(&_path), "dummy");
}
static void assert_repo_state(git_repository_state_t state)
{
cl_assert_equal_i(state, git_repository_state(_repo));
}
void test_repo_state__none_with_HEAD_attached(void)
{
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__none_with_HEAD_detached(void)
{
cl_git_pass(git_repository_detach_head(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__merge(void)
{
setup_simple_state(GIT_MERGE_HEAD_FILE);
assert_repo_state(GIT_REPOSITORY_STATE_MERGE);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__revert(void)
{
setup_simple_state(GIT_REVERT_HEAD_FILE);
assert_repo_state(GIT_REPOSITORY_STATE_REVERT);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__revert_sequence(void)
{
setup_simple_state(GIT_REVERT_HEAD_FILE);
setup_simple_state(GIT_SEQUENCER_TODO_FILE);
assert_repo_state(GIT_REPOSITORY_STATE_REVERT_SEQUENCE);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__cherry_pick(void)
{
setup_simple_state(GIT_CHERRYPICK_HEAD_FILE);
assert_repo_state(GIT_REPOSITORY_STATE_CHERRYPICK);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__cherrypick_sequence(void)
{
setup_simple_state(GIT_CHERRYPICK_HEAD_FILE);
setup_simple_state(GIT_SEQUENCER_TODO_FILE);
assert_repo_state(GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__bisect(void)
{
setup_simple_state(GIT_BISECT_LOG_FILE);
assert_repo_state(GIT_REPOSITORY_STATE_BISECT);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__rebase_interactive(void)
{
setup_simple_state(GIT_REBASE_MERGE_INTERACTIVE_FILE);
assert_repo_state(GIT_REPOSITORY_STATE_REBASE_INTERACTIVE);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__rebase_merge(void)
{
setup_simple_state(GIT_REBASE_MERGE_DIR "whatever");
assert_repo_state(GIT_REPOSITORY_STATE_REBASE_MERGE);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__rebase(void)
{
setup_simple_state(GIT_REBASE_APPLY_REBASING_FILE);
assert_repo_state(GIT_REPOSITORY_STATE_REBASE);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__apply_mailbox(void)
{
setup_simple_state(GIT_REBASE_APPLY_APPLYING_FILE);
assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
void test_repo_state__apply_mailbox_or_rebase(void)
{
setup_simple_state(GIT_REBASE_APPLY_DIR "whatever");
assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE);
cl_git_pass(git_repository_state_cleanup(_repo));
assert_repo_state(GIT_REPOSITORY_STATE_NONE);
}
+295
View File
@@ -0,0 +1,295 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "repo/repo_helpers.h"
#define CLEAR_FOR_CORE_FILEMODE(M) ((M) &= ~0177)
static git_repository *_repo = NULL;
static mode_t g_umask = 0;
static git_buf _global_path = GIT_BUF_INIT;
static const char *fixture_repo;
static const char *fixture_templates;
void test_repo_template__initialize(void)
{
_repo = NULL;
/* load umask if not already loaded */
if (!g_umask) {
g_umask = p_umask(022);
(void)p_umask(g_umask);
}
}
void test_repo_template__cleanup(void)
{
git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
_global_path.ptr);
git_buf_dispose(&_global_path);
cl_fixture_cleanup("tmp_global_path");
if (fixture_repo) {
cl_fixture_cleanup(fixture_repo);
fixture_repo = NULL;
}
if (fixture_templates) {
cl_fixture_cleanup(fixture_templates);
fixture_templates = NULL;
}
git_repository_free(_repo);
_repo = NULL;
}
static void assert_hooks_match(
const char *template_dir,
const char *repo_dir,
const char *hook_path,
bool core_filemode)
{
git_buf expected = GIT_BUF_INIT;
git_buf actual = GIT_BUF_INIT;
struct stat expected_st, st;
cl_git_pass(git_buf_joinpath(&expected, template_dir, hook_path));
cl_git_pass(git_path_lstat(expected.ptr, &expected_st));
cl_git_pass(git_buf_joinpath(&actual, repo_dir, hook_path));
cl_git_pass(git_path_lstat(actual.ptr, &st));
cl_assert(expected_st.st_size == st.st_size);
if (GIT_MODE_TYPE(expected_st.st_mode) != GIT_FILEMODE_LINK) {
mode_t expected_mode =
GIT_MODE_TYPE(expected_st.st_mode) |
(GIT_PERMS_FOR_WRITE(expected_st.st_mode) & ~g_umask);
if (!core_filemode) {
CLEAR_FOR_CORE_FILEMODE(expected_mode);
CLEAR_FOR_CORE_FILEMODE(st.st_mode);
}
cl_assert_equal_i_fmt(expected_mode, st.st_mode, "%07o");
}
git_buf_dispose(&expected);
git_buf_dispose(&actual);
}
static void assert_mode_seems_okay(
const char *base, const char *path,
git_filemode_t expect_mode, bool expect_setgid, bool core_filemode)
{
git_buf full = GIT_BUF_INIT;
struct stat st;
cl_git_pass(git_buf_joinpath(&full, base, path));
cl_git_pass(git_path_lstat(full.ptr, &st));
git_buf_dispose(&full);
if (!core_filemode) {
CLEAR_FOR_CORE_FILEMODE(expect_mode);
CLEAR_FOR_CORE_FILEMODE(st.st_mode);
expect_setgid = false;
}
if (S_ISGID != 0)
cl_assert_equal_b(expect_setgid, (st.st_mode & S_ISGID) != 0);
cl_assert_equal_b(
GIT_PERMS_IS_EXEC(expect_mode), GIT_PERMS_IS_EXEC(st.st_mode));
cl_assert_equal_i_fmt(
GIT_MODE_TYPE(expect_mode), GIT_MODE_TYPE(st.st_mode), "%07o");
}
static void setup_repo(const char *name, git_repository_init_options *opts)
{
cl_git_pass(git_repository_init_ext(&_repo, name, opts));
fixture_repo = name;
}
static void setup_templates(const char *name, bool setup_globally)
{
git_buf path = GIT_BUF_INIT;
cl_fixture_sandbox("template");
if (strcmp(name, "template"))
cl_must_pass(p_rename("template", name));
fixture_templates = name;
/*
* Create a symlink from link.sample to update.sample if the filesystem
* supports it.
*/
cl_git_pass(git_buf_join3(&path, '/', name, "hooks", "link.sample"));
#ifdef GIT_WIN32
cl_git_mkfile(path.ptr, "#!/bin/sh\necho hello, world\n");
#else
cl_must_pass(p_symlink("update.sample", path.ptr));
#endif
git_buf_clear(&path);
/* Create a file starting with a dot */
cl_git_pass(git_buf_join3(&path, '/', name, "hooks", ".dotfile"));
cl_git_mkfile(path.ptr, "something\n");
git_buf_clear(&path);
if (setup_globally) {
cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), name));
create_tmp_global_config("tmp_global_path", "init.templatedir", path.ptr);
}
git_buf_dispose(&path);
}
static void validate_templates(git_repository *repo, const char *template_path)
{
git_buf path = GIT_BUF_INIT, expected = GIT_BUF_INIT, actual = GIT_BUF_INIT;
int filemode;
cl_git_pass(git_buf_joinpath(&path, template_path, "description"));
cl_git_pass(git_futils_readbuffer(&expected, path.ptr));
git_buf_clear(&path);
cl_git_pass(git_buf_joinpath(&path, git_repository_path(repo), "description"));
cl_git_pass(git_futils_readbuffer(&actual, path.ptr));
cl_assert_equal_s(expected.ptr, actual.ptr);
filemode = cl_repo_get_bool(repo, "core.filemode");
assert_hooks_match(
template_path, git_repository_path(repo),
"hooks/update.sample", filemode);
assert_hooks_match(
template_path, git_repository_path(repo),
"hooks/link.sample", filemode);
assert_hooks_match(
template_path, git_repository_path(repo),
"hooks/.dotfile", filemode);
git_buf_dispose(&expected);
git_buf_dispose(&actual);
git_buf_dispose(&path);
}
void test_repo_template__external_templates_specified_in_options(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
opts.template_path = "template";
setup_templates("template", false);
setup_repo("templated.git", &opts);
validate_templates(_repo, "template");
}
void test_repo_template__external_templates_specified_in_config(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
setup_templates("template", true);
setup_repo("templated.git", &opts);
validate_templates(_repo, "template");
}
void test_repo_template__external_templates_with_leading_dot(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
setup_templates(".template_with_leading_dot", true);
setup_repo("templated.git", &opts);
validate_templates(_repo, ".template_with_leading_dot");
}
void test_repo_template__extended_with_template_and_shared_mode(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
const char *repo_path;
int filemode;
opts.flags = GIT_REPOSITORY_INIT_MKPATH |
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
opts.template_path = "template";
opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP;
setup_templates("template", false);
setup_repo("init_shared_from_tpl", &opts);
filemode = cl_repo_get_bool(_repo, "core.filemode");
repo_path = git_repository_path(_repo);
assert_mode_seems_okay(repo_path, "hooks",
GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode);
assert_mode_seems_okay(repo_path, "info",
GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode);
assert_mode_seems_okay(repo_path, "description",
GIT_FILEMODE_BLOB, false, filemode);
validate_templates(_repo, "template");
}
void test_repo_template__templated_head_is_used(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
git_buf head = GIT_BUF_INIT;
opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
setup_templates("template", true);
cl_git_mkfile("template/HEAD", "foobar\n");
setup_repo("repo", &opts);
cl_git_pass(git_futils_readbuffer(&head, "repo/.git/HEAD"));
cl_assert_equal_s("foobar\n", head.ptr);
git_buf_dispose(&head);
}
void test_repo_template__initial_head_option_overrides_template_head(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
git_buf head = GIT_BUF_INIT;
opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
opts.initial_head = "manual";
setup_templates("template", true);
cl_git_mkfile("template/HEAD", "foobar\n");
setup_repo("repo", &opts);
cl_git_pass(git_futils_readbuffer(&head, "repo/.git/HEAD"));
cl_assert_equal_s("ref: refs/heads/manual\n", head.ptr);
git_buf_dispose(&head);
}
void test_repo_template__empty_template_path(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
opts.template_path = "";
setup_repo("foo", &opts);
}