X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=tests%2Flibgit2%2Frepo%2Ftemplate.c;fp=tests%2Flibgit2%2Frepo%2Ftemplate.c;h=e8fe266cfc34d7469ae071163176b3ff07008e58;hb=cc43b7442ea25e6846b10718cd9b1f1972fcd2fc;hp=0000000000000000000000000000000000000000;hpb=ab27e46e5f1c31d3d7b7aa560dab3bb70bd1218b;p=libgit2.git diff --git a/tests/libgit2/repo/template.c b/tests/libgit2/repo/template.c new file mode 100644 index 000000000..e8fe266cf --- /dev/null +++ b/tests/libgit2/repo/template.c @@ -0,0 +1,305 @@ +#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_str _global_path = GIT_STR_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_str_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_str expected = GIT_STR_INIT; + git_str actual = GIT_STR_INIT; + struct stat expected_st, st; + + cl_git_pass(git_str_joinpath(&expected, template_dir, hook_path)); + cl_git_pass(git_fs_path_lstat(expected.ptr, &expected_st)); + + cl_git_pass(git_str_joinpath(&actual, repo_dir, hook_path)); + cl_git_pass(git_fs_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_str_dispose(&expected); + git_str_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_str full = GIT_STR_INIT; + struct stat st; + + cl_git_pass(git_str_joinpath(&full, base, path)); + cl_git_pass(git_fs_path_lstat(full.ptr, &st)); + git_str_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_str path = GIT_STR_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_str_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_str_clear(&path); + + /* Create a file starting with a dot */ + cl_git_pass(git_str_join3(&path, '/', name, "hooks", ".dotfile")); + cl_git_mkfile(path.ptr, "something\n"); + + git_str_clear(&path); + + if (setup_globally) { + cl_git_pass(git_str_joinpath(&path, clar_sandbox_path(), name)); + create_tmp_global_config("tmp_global_path", "init.templatedir", path.ptr); + } + + git_str_dispose(&path); +} + +static void validate_templates(git_repository *repo, const char *template_path) +{ + git_str path = GIT_STR_INIT, expected = GIT_STR_INIT, actual = GIT_STR_INIT; + int filemode; + + cl_git_pass(git_str_joinpath(&path, template_path, "description")); + cl_git_pass(git_futils_readbuffer(&expected, path.ptr)); + + git_str_clear(&path); + + cl_git_pass(git_str_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_str_dispose(&expected); + git_str_dispose(&actual); + git_str_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_str head = GIT_STR_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_str_dispose(&head); +} + +void test_repo_template__initial_head_option_overrides_template_head(void) +{ + git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; + git_str head = GIT_STR_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_str_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); +} + +void test_repo_template__nonexistent_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 = "/tmp/path/that/does/not/exist/for/libgit2/test"; + + setup_repo("bar", &opts); +}