summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2018-10-20 05:43:40 -0700
committerEdward Thomson <ethomson@edwardthomson.com>2018-10-20 17:07:18 +0100
commitda500cc607f1f30cea822087f3aaeb6b6727ff74 (patch)
tree277309ed61ef82926891474942c25c6c92e810a7
parent3f0caa15298ae617aba1eac52dac8cc98318cd52 (diff)
downloadlibgit2-ethomson/win_symlinks.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.c98
-rw-r--r--tests/repo/init.c90
-rw-r--r--tests/repo/repo_helpers.c28
-rw-r--r--tests/repo/repo_helpers.h1
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);