Commit e4ac4000 by Edward Thomson

checkout tests: test symlinks based on support, not platform

When testing whether symlinks are correctly checked out, examine the
`core.symlinks` configuration option to determine if symlinks are
supported in a repository, don't simply assume that Windows means that
symbolic links are not supported.

Further, when testing the expected default behavior of `core.symlinks`,
test the filesystem's support to determine if symlinks are supported.

Finally, ensure that `core.symlinks=true` fails on a system where
symlinks are actually not supported.  This aligns with the behavior of
Git for Windows.
parent 7b6875f4
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "git2/repository.h" #include "git2/repository.h"
#include "git2/sys/index.h" #include "git2/sys/index.h"
#include "fileops.h" #include "fileops.h"
#include "repository.h"
static git_repository *g_repo; static git_repository *g_repo;
static git_index *g_index; static git_index *g_index;
...@@ -184,28 +185,35 @@ static void ensure_workdir(const char *path, int mode, const char *oid_str) ...@@ -184,28 +185,35 @@ static void ensure_workdir(const char *path, int mode, const char *oid_str)
ensure_workdir_oid(path, oid_str); ensure_workdir_oid(path, oid_str);
} }
static void ensure_workdir_link(const char *path, const char *target) static void ensure_workdir_link(
git_repository *repo,
const char *path,
const char *target)
{ {
#ifdef GIT_WIN32 int symlinks;
ensure_workdir_contents(path, target);
#else
git_buf fullpath = GIT_BUF_INIT;
char actual[1024];
struct stat st;
int len;
cl_git_pass( cl_git_pass(git_repository__cvar(&symlinks, repo, GIT_CVAR_SYMLINKS));
git_buf_joinpath(&fullpath, git_repository_workdir(g_repo), path));
cl_git_pass(p_lstat(git_buf_cstr(&fullpath), &st)); if (!symlinks) {
cl_assert(S_ISLNK(st.st_mode)); ensure_workdir_contents(path, target);
} else {
git_buf fullpath = GIT_BUF_INIT;
char actual[1024];
struct stat st;
int len;
cl_assert((len = p_readlink(git_buf_cstr(&fullpath), actual, 1024)) > 0); cl_git_pass(
actual[len] = '\0'; git_buf_joinpath(&fullpath, git_repository_workdir(g_repo), path));
cl_assert(strcmp(actual, target) == 0);
git_buf_dispose(&fullpath); cl_git_pass(p_lstat(git_buf_cstr(&fullpath), &st));
#endif cl_assert(S_ISLNK(st.st_mode));
cl_assert((len = p_readlink(git_buf_cstr(&fullpath), actual, 1024)) > 0);
actual[len] = '\0';
cl_assert(strcmp(actual, target) == 0);
git_buf_dispose(&fullpath);
}
} }
void test_checkout_conflict__ignored(void) void test_checkout_conflict__ignored(void)
...@@ -415,8 +423,8 @@ void test_checkout_conflict__links(void) ...@@ -415,8 +423,8 @@ void test_checkout_conflict__links(void)
cl_git_pass(git_checkout_index(g_repo, g_index, &opts)); cl_git_pass(git_checkout_index(g_repo, g_index, &opts));
/* Conflicts with links always keep the ours side (even with -Xtheirs) */ /* Conflicts with links always keep the ours side (even with -Xtheirs) */
ensure_workdir_link("link-1", LINK_OURS_TARGET); ensure_workdir_link(g_repo, "link-1", LINK_OURS_TARGET);
ensure_workdir_link("link-2", LINK_OURS_TARGET); ensure_workdir_link(g_repo, "link-2", LINK_OURS_TARGET);
} }
void test_checkout_conflict__add_add(void) void test_checkout_conflict__add_add(void)
...@@ -684,7 +692,7 @@ void test_checkout_conflict__renames(void) ...@@ -684,7 +692,7 @@ void test_checkout_conflict__renames(void)
void test_checkout_conflict__rename_keep_ours(void) void test_checkout_conflict__rename_keep_ours(void)
{ {
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
struct checkout_index_entry checkout_index_entries[] = { struct checkout_index_entry checkout_index_entries[] = {
{ 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e", 0, "0a-no-change.txt" }, { 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e", 0, "0a-no-change.txt" },
{ 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" },
...@@ -728,122 +736,122 @@ void test_checkout_conflict__rename_keep_ours(void) ...@@ -728,122 +736,122 @@ void test_checkout_conflict__rename_keep_ours(void)
{ 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 2, "7-both-renamed.txt" }, { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 2, "7-both-renamed.txt" },
{ 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" } { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" }
}; };
struct checkout_name_entry checkout_name_entries[] = { struct checkout_name_entry checkout_name_entries[] = {
{ {
"3a-renamed-in-ours-deleted-in-theirs.txt", "3a-renamed-in-ours-deleted-in-theirs.txt",
"3a-newname-in-ours-deleted-in-theirs.txt", "3a-newname-in-ours-deleted-in-theirs.txt",
"" ""
}, },
{ {
"3b-renamed-in-theirs-deleted-in-ours.txt", "3b-renamed-in-theirs-deleted-in-ours.txt",
"", "",
"3b-newname-in-theirs-deleted-in-ours.txt" "3b-newname-in-theirs-deleted-in-ours.txt"
}, },
{ {
"4a-renamed-in-ours-added-in-theirs.txt", "4a-renamed-in-ours-added-in-theirs.txt",
"4a-newname-in-ours-added-in-theirs.txt", "4a-newname-in-ours-added-in-theirs.txt",
"" ""
}, },
{ {
"4b-renamed-in-theirs-added-in-ours.txt", "4b-renamed-in-theirs-added-in-ours.txt",
"", "",
"4b-newname-in-theirs-added-in-ours.txt" "4b-newname-in-theirs-added-in-ours.txt"
}, },
{ {
"5a-renamed-in-ours-added-in-theirs.txt", "5a-renamed-in-ours-added-in-theirs.txt",
"5a-newname-in-ours-added-in-theirs.txt", "5a-newname-in-ours-added-in-theirs.txt",
"5a-renamed-in-ours-added-in-theirs.txt" "5a-renamed-in-ours-added-in-theirs.txt"
}, },
{ {
"5b-renamed-in-theirs-added-in-ours.txt", "5b-renamed-in-theirs-added-in-ours.txt",
"5b-renamed-in-theirs-added-in-ours.txt", "5b-renamed-in-theirs-added-in-ours.txt",
"5b-newname-in-theirs-added-in-ours.txt" "5b-newname-in-theirs-added-in-ours.txt"
}, },
{ {
"6-both-renamed-1-to-2.txt", "6-both-renamed-1-to-2.txt",
"6-both-renamed-1-to-2-ours.txt", "6-both-renamed-1-to-2-ours.txt",
"6-both-renamed-1-to-2-theirs.txt" "6-both-renamed-1-to-2-theirs.txt"
}, },
{ {
"7-both-renamed-side-1.txt", "7-both-renamed-side-1.txt",
"7-both-renamed.txt", "7-both-renamed.txt",
"7-both-renamed-side-1.txt" "7-both-renamed-side-1.txt"
}, },
{ {
"7-both-renamed-side-2.txt", "7-both-renamed-side-2.txt",
"7-both-renamed-side-2.txt", "7-both-renamed-side-2.txt",
"7-both-renamed.txt" "7-both-renamed.txt"
} }
}; };
opts.checkout_strategy |= GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS; opts.checkout_strategy |= GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS;
create_index(checkout_index_entries, 41); create_index(checkout_index_entries, 41);
create_index_names(checkout_name_entries, 9); create_index_names(checkout_name_entries, 9);
cl_git_pass(git_index_write(g_index)); cl_git_pass(git_index_write(g_index));
cl_git_pass(git_checkout_index(g_repo, g_index, &opts)); cl_git_pass(git_checkout_index(g_repo, g_index, &opts));
ensure_workdir("0a-no-change.txt", ensure_workdir("0a-no-change.txt",
0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e"); 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e");
ensure_workdir("0b-duplicated-in-ours.txt", ensure_workdir("0b-duplicated-in-ours.txt",
0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6"); 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6");
ensure_workdir("0b-rewritten-in-ours.txt", ensure_workdir("0b-rewritten-in-ours.txt",
0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e"); 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e");
ensure_workdir("0c-duplicated-in-theirs.txt", ensure_workdir("0c-duplicated-in-theirs.txt",
0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31"); 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31");
ensure_workdir("0c-rewritten-in-theirs.txt", ensure_workdir("0c-rewritten-in-theirs.txt",
0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09"); 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09");
ensure_workdir("1a-newname-in-ours-edited-in-theirs.txt", ensure_workdir("1a-newname-in-ours-edited-in-theirs.txt",
0100644, "0d872f8e871a30208305978ecbf9e66d864f1638"); 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638");
ensure_workdir("1a-newname-in-ours.txt", ensure_workdir("1a-newname-in-ours.txt",
0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb"); 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb");
ensure_workdir("1b-newname-in-theirs-edited-in-ours.txt", ensure_workdir("1b-newname-in-theirs-edited-in-ours.txt",
0100644, "ed9523e62e453e50dd9be1606af19399b96e397a"); 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a");
ensure_workdir("1b-newname-in-theirs.txt", ensure_workdir("1b-newname-in-theirs.txt",
0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136"); 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136");
ensure_workdir("2-newname-in-both.txt", ensure_workdir("2-newname-in-both.txt",
0100644, "178940b450f238a56c0d75b7955cb57b38191982"); 0100644, "178940b450f238a56c0d75b7955cb57b38191982");
ensure_workdir("3a-newname-in-ours-deleted-in-theirs.txt", ensure_workdir("3a-newname-in-ours-deleted-in-theirs.txt",
0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9"); 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9");
ensure_workdir("3b-newname-in-theirs-deleted-in-ours.txt", ensure_workdir("3b-newname-in-theirs-deleted-in-ours.txt",
0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495"); 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495");
ensure_workdir("4a-newname-in-ours-added-in-theirs.txt", ensure_workdir("4a-newname-in-ours-added-in-theirs.txt",
0100644, "227792b52aaa0b238bea00ec7e509b02623f168c"); 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c");
ensure_workdir("4b-newname-in-theirs-added-in-ours.txt", ensure_workdir("4b-newname-in-theirs-added-in-ours.txt",
0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9"); 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9");
ensure_workdir("5a-newname-in-ours-added-in-theirs.txt", ensure_workdir("5a-newname-in-ours-added-in-theirs.txt",
0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436"); 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436");
ensure_workdir("5b-newname-in-theirs-added-in-ours.txt", ensure_workdir("5b-newname-in-theirs-added-in-ours.txt",
0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced"); 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced");
ensure_workdir("6-both-renamed-1-to-2-ours.txt", ensure_workdir("6-both-renamed-1-to-2-ours.txt",
0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450"); 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450");
ensure_workdir("7-both-renamed.txt", ensure_workdir("7-both-renamed.txt",
0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11"); 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11");
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "git2/checkout.h" #include "git2/checkout.h"
#include "refs.h" #include "refs.h"
#include "path.h" #include "path.h"
#include "repository.h"
#ifdef GIT_WIN32 #ifdef GIT_WIN32
# include <windows.h> # include <windows.h>
...@@ -91,6 +92,18 @@ static void assert_name_is(const char *expected) ...@@ -91,6 +92,18 @@ static void assert_name_is(const char *expected)
free(actual); free(actual);
} }
static int symlink_or_fake(git_repository *repo, const char *a, const char *b)
{
int symlinks;
cl_git_pass(git_repository__cvar(&symlinks, repo, GIT_CVAR_SYMLINKS));
if (symlinks)
return p_symlink(a, b);
else
return git_futils_fake_symlink(a, b);
}
void test_checkout_icase__refuses_to_overwrite_files_for_files(void) void test_checkout_icase__refuses_to_overwrite_files_for_files(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING;
...@@ -117,7 +130,7 @@ void test_checkout_icase__refuses_to_overwrite_links_for_files(void) ...@@ -117,7 +130,7 @@ void test_checkout_icase__refuses_to_overwrite_links_for_files(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING;
cl_must_pass(p_symlink("../tmp", "testrepo/BRANCH_FILE.txt")); cl_must_pass(symlink_or_fake(repo, "../tmp", "testrepo/BRANCH_FILE.txt"));
cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts)); cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts));
...@@ -129,7 +142,7 @@ void test_checkout_icase__overwrites_links_for_files_when_forced(void) ...@@ -129,7 +142,7 @@ void test_checkout_icase__overwrites_links_for_files_when_forced(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_must_pass(p_symlink("../tmp", "testrepo/NEW.txt")); cl_must_pass(symlink_or_fake(repo, "../tmp", "testrepo/NEW.txt"));
cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts)); cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts));
...@@ -205,7 +218,7 @@ void test_checkout_icase__refuses_to_overwrite_links_for_folders(void) ...@@ -205,7 +218,7 @@ void test_checkout_icase__refuses_to_overwrite_links_for_folders(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING;
cl_must_pass(p_symlink("..", "testrepo/A")); cl_must_pass(symlink_or_fake(repo, "..", "testrepo/A"));
cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts)); cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts));
...@@ -217,7 +230,7 @@ void test_checkout_icase__overwrites_links_for_folders_when_forced(void) ...@@ -217,7 +230,7 @@ void test_checkout_icase__overwrites_links_for_folders_when_forced(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_must_pass(p_symlink("..", "testrepo/A")); cl_must_pass(symlink_or_fake(repo, "..", "testrepo/A"));
cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts)); cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts));
......
...@@ -136,6 +136,25 @@ void test_checkout_index__honor_coreautocrlf_setting_set_to_true(void) ...@@ -136,6 +136,25 @@ void test_checkout_index__honor_coreautocrlf_setting_set_to_true(void)
#endif #endif
} }
static bool supports_symlinks(const char *dir)
{
git_buf path = GIT_BUF_INIT;
struct stat st;
bool supports_symlinks = 1;
cl_git_pass(git_buf_joinpath(&path, dir, "test"));
/* see if symlinks are supported in the "symlink" directory */
if (p_symlink("target", path.ptr) < 0 ||
p_lstat(path.ptr, &st) < 0 ||
! (S_ISLNK(st.st_mode)))
supports_symlinks = 0;
git_buf_dispose(&path);
return supports_symlinks;
}
void test_checkout_index__honor_coresymlinks_default(void) void test_checkout_index__honor_coresymlinks_default(void)
{ {
git_repository *repo; git_repository *repo;
...@@ -162,10 +181,9 @@ void test_checkout_index__honor_coresymlinks_default(void) ...@@ -162,10 +181,9 @@ void test_checkout_index__honor_coresymlinks_default(void)
git_object_free(target); git_object_free(target);
git_repository_free(repo); git_repository_free(repo);
#ifdef GIT_WIN32 if (!supports_symlinks("symlink")) {
check_file_contents("./symlink/link_to_new.txt", "new.txt"); check_file_contents("./symlink/link_to_new.txt", "new.txt");
#else } else {
{
char link_data[1024]; char link_data[1024];
size_t link_size = 1024; size_t link_size = 1024;
...@@ -175,14 +193,33 @@ void test_checkout_index__honor_coresymlinks_default(void) ...@@ -175,14 +193,33 @@ void test_checkout_index__honor_coresymlinks_default(void)
cl_assert_equal_s(link_data, "new.txt"); cl_assert_equal_s(link_data, "new.txt");
check_file_contents("./symlink/link_to_new.txt", "my new file\n"); check_file_contents("./symlink/link_to_new.txt", "my new file\n");
} }
#endif
cl_fixture_cleanup("symlink"); cl_fixture_cleanup("symlink");
} }
void test_checkout_index__coresymlinks_set_to_true_fails_when_unsupported(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
if (supports_symlinks("testrepo")) {
cl_skip();
}
cl_repo_set_bool(g_repo, "core.symlinks", true);
opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING;
cl_git_fail(git_checkout_index(g_repo, NULL, &opts));
}
void test_checkout_index__honor_coresymlinks_setting_set_to_true(void) void test_checkout_index__honor_coresymlinks_setting_set_to_true(void)
{ {
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
char link_data[GIT_PATH_MAX];
size_t link_size = GIT_PATH_MAX;
if (!supports_symlinks("testrepo")) {
cl_skip();
}
cl_repo_set_bool(g_repo, "core.symlinks", true); cl_repo_set_bool(g_repo, "core.symlinks", true);
...@@ -190,20 +227,11 @@ void test_checkout_index__honor_coresymlinks_setting_set_to_true(void) ...@@ -190,20 +227,11 @@ void test_checkout_index__honor_coresymlinks_setting_set_to_true(void)
cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
#ifdef GIT_WIN32 link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size);
check_file_contents("./testrepo/link_to_new.txt", "new.txt"); link_data[link_size] = '\0';
#else cl_assert_equal_i(link_size, strlen("new.txt"));
{ cl_assert_equal_s(link_data, "new.txt");
char link_data[1024]; check_file_contents("./testrepo/link_to_new.txt", "my new file\n");
size_t link_size = 1024;
link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size);
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("./testrepo/link_to_new.txt", "my new file\n");
}
#endif
} }
void test_checkout_index__honor_coresymlinks_setting_set_to_false(void) void test_checkout_index__honor_coresymlinks_setting_set_to_false(void)
...@@ -474,7 +502,7 @@ void test_checkout_index__can_overcome_name_clashes(void) ...@@ -474,7 +502,7 @@ void test_checkout_index__can_overcome_name_clashes(void)
cl_assert(git_path_isfile("./testrepo/path0/file0")); cl_assert(git_path_isfile("./testrepo/path0/file0"));
opts.checkout_strategy = opts.checkout_strategy =
GIT_CHECKOUT_SAFE | GIT_CHECKOUT_SAFE |
GIT_CHECKOUT_RECREATE_MISSING | GIT_CHECKOUT_RECREATE_MISSING |
GIT_CHECKOUT_ALLOW_CONFLICTS; GIT_CHECKOUT_ALLOW_CONFLICTS;
cl_git_pass(git_checkout_index(g_repo, index, &opts)); cl_git_pass(git_checkout_index(g_repo, index, &opts));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment