diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2018-10-20 05:43:40 -0700 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2018-10-20 17:07:18 +0100 |
commit | da500cc607f1f30cea822087f3aaeb6b6727ff74 (patch) | |
tree | 277309ed61ef82926891474942c25c6c92e810a7 | |
parent | 3f0caa15298ae617aba1eac52dac8cc98318cd52 (diff) | |
download | libgit2-da500cc607f1f30cea822087f3aaeb6b6727ff74.tar.gz |
symlink tests: test symbolic links on windowsethomson/win_symlinks
Test updated symbolic link creation on Windows. Ensure that we emulate
Git for Windows behavior. Ensure that when `core.symlinks=true` is set
in a global configuration that new repositories are created without a
`core.symlinks` setting, and that when `core.symlinks` is unset that
`core.symlinks=false` in set in the repository. Further ensure that
checkout honors the expected `core.symlinks` defaults on Windows.
-rw-r--r-- | tests/checkout/index.c | 98 | ||||
-rw-r--r-- | tests/repo/init.c | 90 | ||||
-rw-r--r-- | tests/repo/repo_helpers.c | 28 | ||||
-rw-r--r-- | tests/repo/repo_helpers.h | 1 |
4 files changed, 151 insertions, 66 deletions
diff --git a/tests/checkout/index.c b/tests/checkout/index.c index 4d86ba196..65a121d76 100644 --- a/tests/checkout/index.c +++ b/tests/checkout/index.c @@ -5,8 +5,10 @@ #include "fileops.h" #include "repository.h" #include "remote.h" +#include "repo/repo_helpers.h" static git_repository *g_repo; +static git_buf g_global_path = GIT_BUF_INIT; void test_checkout_index__initialize(void) { @@ -22,21 +24,29 @@ void test_checkout_index__initialize(void) cl_git_rewritefile( "./testrepo/.gitattributes", "* text eol=lf\n"); + + git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, + &g_global_path); } void test_checkout_index__cleanup(void) { + git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, + g_global_path.ptr); + git_buf_dispose(&g_global_path); + cl_git_sandbox_cleanup(); - /* try to remove alternative dir */ - if (git_path_isdir("alternative")) - git_futils_rmdir_r("alternative", NULL, GIT_RMDIR_REMOVE_FILES); + /* try to remove directories created by tests */ + cl_fixture_cleanup("alternative"); + cl_fixture_cleanup("symlink"); + cl_fixture_cleanup("symlink.git"); + cl_fixture_cleanup("tmp_global_path"); } void test_checkout_index__cannot_checkout_a_bare_repository(void) { - test_checkout_index__cleanup(); - + cl_git_sandbox_cleanup(); g_repo = cl_git_sandbox_init("testrepo.git"); cl_git_fail(git_checkout_index(g_repo, NULL, NULL)); @@ -136,23 +146,20 @@ void test_checkout_index__honor_coreautocrlf_setting_set_to_true(void) #endif } -void test_checkout_index__honor_coresymlinks_default(void) +static void populate_symlink_workdir(void) { git_repository *repo; git_remote *origin; git_object *target; - char cwd[GIT_PATH_MAX]; const char *url = git_repository_path(g_repo); - cl_assert(getcwd(cwd, sizeof(cwd)) != NULL); - cl_assert_equal_i(0, p_mkdir("readonly", 0555)); /* Read-only directory */ - cl_assert_equal_i(0, chdir("readonly")); cl_git_pass(git_repository_init(&repo, "../symlink.git", true)); - cl_assert_equal_i(0, chdir(cwd)); - cl_assert_equal_i(0, p_mkdir("symlink", 0777)); cl_git_pass(git_repository_set_workdir(repo, "symlink", 1)); + /* Delete the `origin` repo (if it exists) so we can recreate it. */ + git_remote_delete(repo, GIT_REMOTE_ORIGIN); + cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); cl_git_pass(git_remote_fetch(origin, NULL, NULL, NULL)); git_remote_free(origin); @@ -161,23 +168,54 @@ void test_checkout_index__honor_coresymlinks_default(void) cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL)); git_object_free(target); git_repository_free(repo); +} - if (!filesystem_supports_symlinks("symlink/test")) { - check_file_contents("./symlink/link_to_new.txt", "new.txt"); - } else { - char link_data[1024]; - int link_size = 1024; +void test_checkout_index__honor_coresymlinks_default_true(void) +{ + char link_data[GIT_PATH_MAX]; + int link_size = GIT_PATH_MAX; - link_size = p_readlink("./symlink/link_to_new.txt", link_data, link_size); - cl_assert(link_size >= 0); + cl_must_pass(p_mkdir("symlink", 0777)); - link_data[link_size] = '\0'; - cl_assert_equal_i(link_size, strlen("new.txt")); - cl_assert_equal_s(link_data, "new.txt"); - check_file_contents("./symlink/link_to_new.txt", "my new file\n"); - } + if (!filesystem_supports_symlinks("symlink/test")) + cl_skip(); - cl_fixture_cleanup("symlink"); +#ifdef GIT_WIN32 + /* + * Windows explicitly requires the global configuration to have + * core.symlinks=true in addition to actual filesystem support. + */ + create_tmp_global_config("tmp_global_path", "core.symlinks", "true"); +#endif + + populate_symlink_workdir(); + + link_size = p_readlink("./symlink/link_to_new.txt", link_data, link_size); + cl_assert(link_size >= 0); + + link_data[link_size] = '\0'; + cl_assert_equal_i(link_size, strlen("new.txt")); + cl_assert_equal_s(link_data, "new.txt"); + check_file_contents("./symlink/link_to_new.txt", "my new file\n"); +} + +void test_checkout_index__honor_coresymlinks_default_false(void) +{ + cl_must_pass(p_mkdir("symlink", 0777)); + +#ifndef GIT_WIN32 + /* + * This test is largely for Windows platforms to ensure that + * we respect an unset core.symlinks even when the platform + * supports symlinks. Bail entirely on POSIX platforms that + * do support symlinks. + */ + if (filesystem_supports_symlinks("symlink/test")) + cl_skip(); +#endif + + populate_symlink_workdir(); + check_file_contents("./symlink/link_to_new.txt", "new.txt"); } void test_checkout_index__coresymlinks_set_to_true_fails_when_unsupported(void) @@ -558,9 +596,9 @@ void test_checkout_index__can_update_prefixed_files(void) void test_checkout_index__can_checkout_a_newly_initialized_repository(void) { - test_checkout_index__cleanup(); - + cl_git_sandbox_cleanup(); g_repo = cl_git_sandbox_init("empty_standard_repo"); + cl_git_remove_placeholders(git_repository_path(g_repo), "dummy-marker.txt"); cl_git_pass(git_checkout_index(g_repo, NULL, NULL)); @@ -570,8 +608,7 @@ void test_checkout_index__issue_1397(void) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; - test_checkout_index__cleanup(); - + cl_git_sandbox_cleanup(); g_repo = cl_git_sandbox_init("issue_1397"); cl_repo_set_bool(g_repo, "core.autocrlf", true); @@ -624,8 +661,7 @@ void test_checkout_index__target_directory_from_bare(void) checkout_counts cts; memset(&cts, 0, sizeof(cts)); - test_checkout_index__cleanup(); - + cl_git_sandbox_cleanup(); g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert(git_repository_is_bare(g_repo)); diff --git a/tests/repo/init.c b/tests/repo/init.c index 6818bf6a8..2611f05c7 100644 --- a/tests/repo/init.c +++ b/tests/repo/init.c @@ -4,6 +4,7 @@ #include "config.h" #include "path.h" #include "config/config_helpers.h" +#include "repo/repo_helpers.h" enum repo_mode { STANDARD_REPOSITORY = 0, @@ -12,7 +13,6 @@ enum repo_mode { static git_repository *_repo = NULL; static git_buf _global_path = GIT_BUF_INIT; -static git_buf _tmp_path = GIT_BUF_INIT; static mode_t g_umask = 0; void test_repo_init__initialize(void) @@ -35,9 +35,7 @@ void test_repo_init__cleanup(void) _global_path.ptr); git_buf_dispose(&_global_path); - if (_tmp_path.size > 0 && git_path_isdir(_tmp_path.ptr)) - git_futils_rmdir_r(_tmp_path.ptr, NULL, GIT_RMDIR_REMOVE_FILES); - git_buf_dispose(&_tmp_path); + cl_fixture_cleanup("tmp_global_path"); } static void cleanup_repository(void *path) @@ -48,19 +46,6 @@ static void cleanup_repository(void *path) cl_fixture_cleanup((const char *)path); } -static void configure_tmp_global_path(git_buf *out) -{ - cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, - GIT_CONFIG_LEVEL_GLOBAL, &_tmp_path)); - cl_git_pass(git_buf_puts(&_tmp_path, ".tmp")); - cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, - GIT_CONFIG_LEVEL_GLOBAL, _tmp_path.ptr)); - - cl_must_pass(p_mkdir(_tmp_path.ptr, 0777)); - - cl_git_pass(git_buf_joinpath(out, _tmp_path.ptr, ".gitconfig")); -} - static void ensure_repository_init( const char *working_directory, int is_bare, @@ -260,10 +245,66 @@ void test_repo_init__detect_ignorecase(void) "core.ignorecase", found_without_match ? true : GIT_ENOTFOUND); } -void test_repo_init__detect_symlinks(void) +/* + * 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 (!filesystem_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", filesystem_supports_symlinks("link") ? GIT_ENOTFOUND : false); +#endif } void test_repo_init__detect_precompose_unicode_required(void) @@ -582,18 +623,7 @@ static const char *template_sandbox(const char *name) static void configure_templatedir(const char *template_path) { - git_buf config_path = GIT_BUF_INIT; - git_buf config_data = GIT_BUF_INIT; - - configure_tmp_global_path(&config_path); - - cl_git_pass(git_buf_printf(&config_data, - "[init]\n\ttemplatedir = \"%s\"\n", template_path)); - - cl_git_mkfile(config_path.ptr, config_data.ptr); - - git_buf_dispose(&config_path); - git_buf_dispose(&config_data); + create_tmp_global_config("tmp_global_path", "init.templatedir", template_path); } static void validate_templates(git_repository *repo, const char *template_path) diff --git a/tests/repo/repo_helpers.c b/tests/repo/repo_helpers.c index 50a201e86..4256314f1 100644 --- a/tests/repo/repo_helpers.c +++ b/tests/repo/repo_helpers.c @@ -24,11 +24,29 @@ void delete_head(git_repository* repo) int filesystem_supports_symlinks(const char *path) { struct stat st; + bool support = 0; - if (p_symlink("target", path) < 0 || - p_lstat(path, &st) < 0 || - !(S_ISLNK(st.st_mode))) - return 0; + if (p_symlink("target", path) == 0) { + if (p_lstat(path, &st) == 0 && S_ISLNK(st.st_mode)) + support = 1; - return 1; + p_unlink(path); + } + + return support; +} + +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); } diff --git a/tests/repo/repo_helpers.h b/tests/repo/repo_helpers.h index f184865ce..2c9aeabee 100644 --- a/tests/repo/repo_helpers.h +++ b/tests/repo/repo_helpers.h @@ -5,3 +5,4 @@ extern void make_head_unborn(git_repository* repo, const char *target); extern void delete_head(git_repository* repo); extern int filesystem_supports_symlinks(const char *path); +extern void create_tmp_global_config(const char *path, const char *key, const char *val); |