diff options
| author | Edward Thomson <ethomson@edwardthomson.com> | 2021-11-16 23:29:22 -0500 |
|---|---|---|
| committer | Edward Thomson <ethomson@edwardthomson.com> | 2022-02-22 22:07:45 -0500 |
| commit | 3344fddc97bbdea9c1b6ebb6f7fb6dbd70b41dfb (patch) | |
| tree | fd6368a72944571c51627b40c592e7d58e0036e1 /tests/libgit2/worktree | |
| parent | 91ba089663f5efc3bd4ba14a5099372cf5ce57a6 (diff) | |
| download | libgit2-3344fddc97bbdea9c1b6ebb6f7fb6dbd70b41dfb.tar.gz | |
refactor: `tests` is now `tests/libgit2`
Like we want to separate libgit2 and utility source code, we want to
separate libgit2 and utility tests. Start by moving all the tests into
libgit2.
Diffstat (limited to 'tests/libgit2/worktree')
| -rw-r--r-- | tests/libgit2/worktree/bare.c | 72 | ||||
| -rw-r--r-- | tests/libgit2/worktree/config.c | 47 | ||||
| -rw-r--r-- | tests/libgit2/worktree/merge.c | 121 | ||||
| -rw-r--r-- | tests/libgit2/worktree/open.c | 126 | ||||
| -rw-r--r-- | tests/libgit2/worktree/reflog.c | 91 | ||||
| -rw-r--r-- | tests/libgit2/worktree/refs.c | 198 | ||||
| -rw-r--r-- | tests/libgit2/worktree/repository.c | 67 | ||||
| -rw-r--r-- | tests/libgit2/worktree/submodule.c | 92 | ||||
| -rw-r--r-- | tests/libgit2/worktree/worktree.c | 647 | ||||
| -rw-r--r-- | tests/libgit2/worktree/worktree_helpers.c | 30 | ||||
| -rw-r--r-- | tests/libgit2/worktree/worktree_helpers.h | 11 |
11 files changed, 1502 insertions, 0 deletions
diff --git a/tests/libgit2/worktree/bare.c b/tests/libgit2/worktree/bare.c new file mode 100644 index 000000000..7234dfffd --- /dev/null +++ b/tests/libgit2/worktree/bare.c @@ -0,0 +1,72 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" +#include "submodule/submodule_helpers.h" + +#define COMMON_REPO "testrepo.git" +#define WORKTREE_REPO "worktree" + +static git_repository *g_repo; + +void test_worktree_bare__initialize(void) +{ + g_repo = cl_git_sandbox_init(COMMON_REPO); + + cl_assert_equal_i(1, git_repository_is_bare(g_repo)); + cl_assert_equal_i(0, git_repository_is_worktree(g_repo)); +} + +void test_worktree_bare__cleanup(void) +{ + cl_fixture_cleanup(WORKTREE_REPO); + cl_git_sandbox_cleanup(); +} + +void test_worktree_bare__list(void) +{ + git_strarray wts; + + cl_git_pass(git_worktree_list(&wts, g_repo)); + cl_assert_equal_i(wts.count, 0); + + git_strarray_dispose(&wts); +} + +void test_worktree_bare__add(void) +{ + git_worktree *wt; + git_repository *wtrepo; + git_strarray wts; + + cl_git_pass(git_worktree_add(&wt, g_repo, "name", WORKTREE_REPO, NULL)); + + cl_git_pass(git_worktree_list(&wts, g_repo)); + cl_assert_equal_i(wts.count, 1); + + cl_git_pass(git_worktree_validate(wt)); + + cl_git_pass(git_repository_open(&wtrepo, WORKTREE_REPO)); + cl_assert_equal_i(0, git_repository_is_bare(wtrepo)); + cl_assert_equal_i(1, git_repository_is_worktree(wtrepo)); + + git_strarray_dispose(&wts); + git_worktree_free(wt); + git_repository_free(wtrepo); +} + +void test_worktree_bare__repository_path(void) +{ + git_worktree *wt; + git_repository *wtrepo; + + cl_git_pass(git_worktree_add(&wt, g_repo, "name", WORKTREE_REPO, NULL)); + cl_assert_equal_s(git_worktree_path(wt), cl_git_sandbox_path(0, WORKTREE_REPO, NULL)); + + cl_git_pass(git_repository_open(&wtrepo, WORKTREE_REPO)); + cl_assert_equal_s(git_repository_path(wtrepo), cl_git_sandbox_path(1, COMMON_REPO, "worktrees", "name", NULL)); + + cl_assert_equal_s(git_repository_commondir(g_repo), git_repository_commondir(wtrepo)); + cl_assert_equal_s(git_repository_workdir(wtrepo), cl_git_sandbox_path(1, WORKTREE_REPO, NULL)); + + git_repository_free(wtrepo); + git_worktree_free(wt); +} diff --git a/tests/libgit2/worktree/config.c b/tests/libgit2/worktree/config.c new file mode 100644 index 000000000..81dcfe1fa --- /dev/null +++ b/tests/libgit2/worktree/config.c @@ -0,0 +1,47 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_config__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_config__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_config__open(void) +{ + git_config *cfg; + + cl_git_pass(git_repository_config(&cfg, fixture.worktree)); + cl_assert(cfg != NULL); + + git_config_free(cfg); +} + +void test_worktree_config__set(void) +{ + git_config *cfg; + int32_t val; + + cl_git_pass(git_repository_config(&cfg, fixture.worktree)); + cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); + git_config_free(cfg); + + /* + * reopen to verify configuration has been set in the + * common dir + */ + cl_git_pass(git_repository_config(&cfg, fixture.repo)); + cl_git_pass(git_config_get_int32(&val, cfg, "core.dummy")); + cl_assert_equal_i(val, 5); + git_config_free(cfg); +} diff --git a/tests/libgit2/worktree/merge.c b/tests/libgit2/worktree/merge.c new file mode 100644 index 000000000..5b7e2a837 --- /dev/null +++ b/tests/libgit2/worktree/merge.c @@ -0,0 +1,121 @@ +#include "clar_libgit2.h" + +#include "worktree_helpers.h" +#include "merge/merge_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +#define MASTER_BRANCH "refs/heads/master" +#define CONFLICT_BRANCH "refs/heads/merge-conflict" + +#define CONFLICT_BRANCH_FILE_TXT \ + "<<<<<<< HEAD\n" \ + "hi\n" \ + "bye!\n" \ + "=======\n" \ + "conflict\n" \ + ">>>>>>> merge-conflict\n" \ + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +static const char *merge_files[] = { + GIT_MERGE_HEAD_FILE, + GIT_ORIG_HEAD_FILE, + GIT_MERGE_MODE_FILE, + GIT_MERGE_MSG_FILE, +}; + +void test_worktree_merge__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_merge__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_merge__merge_head(void) +{ + git_reference *theirs_ref, *ref; + git_annotated_commit *theirs; + + cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref)); + cl_git_pass(git_merge(fixture.worktree, (const git_annotated_commit **)&theirs, 1, NULL, NULL)); + + cl_git_pass(git_reference_lookup(&ref, fixture.worktree, GIT_MERGE_HEAD_FILE)); + + git_reference_free(ref); + git_reference_free(theirs_ref); + git_annotated_commit_free(theirs); +} + +void test_worktree_merge__merge_setup(void) +{ + git_reference *ours_ref, *theirs_ref; + git_annotated_commit *ours, *theirs; + git_str path = GIT_STR_INIT; + unsigned i; + + cl_git_pass(git_reference_lookup(&ours_ref, fixture.worktree, MASTER_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&ours, fixture.worktree, ours_ref)); + + cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref)); + + cl_git_pass(git_merge__setup(fixture.worktree, + ours, (const git_annotated_commit **)&theirs, 1)); + + for (i = 0; i < ARRAY_SIZE(merge_files); i++) { + cl_git_pass(git_str_joinpath(&path, + fixture.worktree->gitdir, + merge_files[i])); + cl_assert(git_fs_path_exists(path.ptr)); + } + + git_str_dispose(&path); + git_reference_free(ours_ref); + git_reference_free(theirs_ref); + git_annotated_commit_free(ours); + git_annotated_commit_free(theirs); +} + +void test_worktree_merge__merge_conflict(void) +{ + git_str path = GIT_STR_INIT, buf = GIT_STR_INIT; + git_reference *theirs_ref; + git_annotated_commit *theirs; + git_index *index; + const git_index_entry *entry; + size_t i, conflicts = 0; + + cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref)); + + cl_git_pass(git_merge(fixture.worktree, + (const git_annotated_commit **)&theirs, 1, NULL, NULL)); + + cl_git_pass(git_repository_index(&index, fixture.worktree)); + for (i = 0; i < git_index_entrycount(index); i++) { + cl_assert(entry = git_index_get_byindex(index, i)); + + if (git_index_entry_is_conflict(entry)) + conflicts++; + } + cl_assert_equal_sz(conflicts, 3); + + git_reference_free(theirs_ref); + git_annotated_commit_free(theirs); + git_index_free(index); + + cl_git_pass(git_str_joinpath(&path, fixture.worktree->workdir, "branch_file.txt")); + cl_git_pass(git_futils_readbuffer(&buf, path.ptr)); + cl_assert_equal_s(buf.ptr, CONFLICT_BRANCH_FILE_TXT); + + git_str_dispose(&path); + git_str_dispose(&buf); +} + diff --git a/tests/libgit2/worktree/open.c b/tests/libgit2/worktree/open.c new file mode 100644 index 000000000..0c3fdc173 --- /dev/null +++ b/tests/libgit2/worktree/open.c @@ -0,0 +1,126 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "worktree.h" +#include "worktree_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +static void assert_worktree_valid(git_repository *wt, const char *parentdir, const char *wtdir) +{ + cl_assert(wt->is_worktree); + + cl_assert_equal_s(wt->workdir, cl_git_sandbox_path(1, wtdir, NULL)); + cl_assert_equal_s(wt->gitlink, cl_git_sandbox_path(0, wtdir, ".git", NULL)); + cl_assert_equal_s(wt->gitdir, cl_git_sandbox_path(1, parentdir, ".git", "worktrees", wtdir, NULL)); +} + +void test_worktree_open__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_open__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_open__repository(void) +{ + assert_worktree_valid(fixture.worktree, COMMON_REPO, WORKTREE_REPO); +} + +void test_worktree_open__repository_through_workdir(void) +{ + git_repository *wt; + + cl_git_pass(git_repository_open(&wt, WORKTREE_REPO)); + assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); + + git_repository_free(wt); +} + +void test_worktree_open__repository_through_gitlink(void) +{ + git_repository *wt; + + cl_git_pass(git_repository_open(&wt, WORKTREE_REPO "/.git")); + assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); + + git_repository_free(wt); +} + +void test_worktree_open__repository_through_gitdir(void) +{ + git_str gitdir_path = GIT_STR_INIT; + git_repository *wt; + + cl_git_pass(git_str_joinpath(&gitdir_path, COMMON_REPO, ".git")); + cl_git_pass(git_str_joinpath(&gitdir_path, gitdir_path.ptr, "worktrees")); + cl_git_pass(git_str_joinpath(&gitdir_path, gitdir_path.ptr, "testrepo-worktree")); + + cl_git_pass(git_repository_open(&wt, gitdir_path.ptr)); + assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); + + git_str_dispose(&gitdir_path); + git_repository_free(wt); +} + +void test_worktree_open__open_discovered_worktree(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + + cl_git_pass(git_repository_discover(&path, + git_repository_workdir(fixture.worktree), false, NULL)); + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert_equal_s(git_repository_workdir(fixture.worktree), + git_repository_workdir(repo)); + + git_buf_dispose(&path); + git_repository_free(repo); +} + +void test_worktree_open__repository_with_nonexistent_parent(void) +{ + git_repository *repo; + + cleanup_fixture_worktree(&fixture); + + cl_fixture_sandbox(WORKTREE_REPO); + cl_git_pass(p_chdir(WORKTREE_REPO)); + cl_git_pass(cl_rename(".gitted", ".git")); + cl_git_pass(p_chdir("..")); + + cl_git_fail(git_repository_open(&repo, WORKTREE_REPO)); + + cl_fixture_cleanup(WORKTREE_REPO); +} + +void test_worktree_open__open_from_repository(void) +{ + git_worktree *opened, *lookedup; + + cl_git_pass(git_worktree_open_from_repository(&opened, fixture.worktree)); + cl_git_pass(git_worktree_lookup(&lookedup, fixture.repo, WORKTREE_REPO)); + + cl_assert_equal_s(opened->name, lookedup->name); + cl_assert_equal_s(opened->gitdir_path, lookedup->gitdir_path); + cl_assert_equal_s(opened->gitlink_path, lookedup->gitlink_path); + cl_assert_equal_s(opened->parent_path, lookedup->parent_path); + cl_assert_equal_s(opened->commondir_path, lookedup->commondir_path); + cl_assert_equal_i(opened->locked, lookedup->locked); + + git_worktree_free(opened); + git_worktree_free(lookedup); +} + +void test_worktree_open__open_from_nonworktree_fails(void) +{ + git_worktree *wt; + + cl_git_fail(git_worktree_open_from_repository(&wt, fixture.repo)); +} diff --git a/tests/libgit2/worktree/reflog.c b/tests/libgit2/worktree/reflog.c new file mode 100644 index 000000000..a68e72dcf --- /dev/null +++ b/tests/libgit2/worktree/reflog.c @@ -0,0 +1,91 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" + +#include "reflog.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +#define REFLOG "refs/heads/testrepo-worktree" +#define REFLOG_MESSAGE "reflog message" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_reflog__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_reflog__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_reflog__read_worktree_HEAD(void) +{ + git_reflog *reflog; + const git_reflog_entry *entry; + + cl_git_pass(git_reflog_read(&reflog, fixture.worktree, "HEAD")); + cl_assert_equal_i(1, git_reflog_entrycount(reflog)); + + entry = git_reflog_entry_byindex(reflog, 0); + cl_assert(entry != NULL); + cl_assert_equal_s("checkout: moving from 099fabac3a9ea935598528c27f866e34089c2eff to testrepo-worktree", git_reflog_entry_message(entry)); + + git_reflog_free(reflog); +} + +void test_worktree_reflog__read_parent_HEAD(void) +{ + git_reflog *reflog; + + cl_git_pass(git_reflog_read(&reflog, fixture.repo, "HEAD")); + /* there is no logs/HEAD in the parent repo */ + cl_assert_equal_i(0, git_reflog_entrycount(reflog)); + + git_reflog_free(reflog); +} + +void test_worktree_reflog__read(void) +{ + git_reflog *reflog; + const git_reflog_entry *entry; + + cl_git_pass(git_reflog_read(&reflog, fixture.worktree, REFLOG)); + cl_assert_equal_i(git_reflog_entrycount(reflog), 1); + + entry = git_reflog_entry_byindex(reflog, 0); + cl_assert(entry != NULL); + cl_assert_equal_s(git_reflog_entry_message(entry), "branch: Created from HEAD"); + + git_reflog_free(reflog); +} + +void test_worktree_reflog__append_then_read(void) +{ + git_reflog *reflog, *parent_reflog; + const git_reflog_entry *entry; + git_reference *head; + git_signature *sig; + const git_oid *oid; + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + cl_assert((oid = git_reference_target(head)) != NULL); + cl_git_pass(git_signature_now(&sig, "foo", "foo@bar")); + + cl_git_pass(git_reflog_read(&reflog, fixture.worktree, REFLOG)); + cl_git_pass(git_reflog_append(reflog, oid, sig, REFLOG_MESSAGE)); + git_reflog_write(reflog); + + cl_git_pass(git_reflog_read(&parent_reflog, fixture.repo, REFLOG)); + entry = git_reflog_entry_byindex(parent_reflog, 0); + cl_assert(git_oid_cmp(oid, &entry->oid_old) == 0); + cl_assert(git_oid_cmp(oid, &entry->oid_cur) == 0); + + git_reference_free(head); + git_signature_free(sig); + git_reflog_free(reflog); + git_reflog_free(parent_reflog); +} diff --git a/tests/libgit2/worktree/refs.c b/tests/libgit2/worktree/refs.c new file mode 100644 index 000000000..557726aaf --- /dev/null +++ b/tests/libgit2/worktree/refs.c @@ -0,0 +1,198 @@ +#include "clar_libgit2.h" +#include "path.h" +#include "refs.h" +#include "worktree.h" +#include "worktree_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_refs__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_refs__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_refs__list(void) +{ + git_strarray refs, wtrefs; + unsigned i, j; + int error = 0; + + cl_git_pass(git_reference_list(&refs, fixture.repo)); + cl_git_pass(git_reference_list(&wtrefs, fixture.worktree)); + + if (refs.count != wtrefs.count) + { + error = GIT_ERROR; + goto exit; + } + + for (i = 0; i < refs.count; i++) + { + int found = 0; + + for (j = 0; j < wtrefs.count; j++) + { + if (!strcmp(refs.strings[i], wtrefs.strings[j])) + { + found = 1; + break; + } + } + + if (!found) + { + error = GIT_ERROR; + goto exit; + } + } + +exit: + git_strarray_dispose(&refs); + git_strarray_dispose(&wtrefs); + cl_git_pass(error); +} + +void test_worktree_refs__read_head(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_fails_when_worktree_wants_linked_repos_HEAD(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_fail(git_repository_set_head(fixture.worktree, git_reference_name(head))); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_fails_when_main_repo_wants_worktree_head(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + cl_git_fail(git_repository_set_head(fixture.repo, git_reference_name(head))); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_works_for_current_HEAD(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_pass(git_repository_set_head(fixture.repo, git_reference_name(head))); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_fails_when_already_checked_out(void) +{ + cl_git_fail(git_repository_set_head(fixture.repo, "refs/heads/testrepo-worktree")); +} + +void test_worktree_refs__delete_fails_for_checked_out_branch(void) +{ + git_reference *branch; + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "testrepo-worktree", GIT_BRANCH_LOCAL)); + cl_git_fail(git_branch_delete(branch)); + + git_reference_free(branch); +} + +void test_worktree_refs__delete_succeeds_after_pruning_worktree(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_reference *branch; + git_worktree *worktree; + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + + cl_git_pass(git_worktree_lookup(&worktree, fixture.repo, fixture.worktreename)); + cl_git_pass(git_worktree_prune(worktree, &opts)); + git_worktree_free(worktree); + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "testrepo-worktree", GIT_BRANCH_LOCAL)); + cl_git_pass(git_branch_delete(branch)); + git_reference_free(branch); +} + +void test_worktree_refs__delete_unrelated_branch_on_worktree(void) +{ + git_reference *branch; + + cl_git_pass(git_branch_lookup(&branch, fixture.worktree, + "merge-conflict", GIT_BRANCH_LOCAL)); + cl_git_pass(git_branch_delete(branch)); + + git_reference_free(branch); +} + +void test_worktree_refs__delete_unrelated_branch_on_parent(void) +{ + git_reference *branch; + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "merge-conflict", GIT_BRANCH_LOCAL)); + cl_git_pass(git_branch_delete(branch)); + + git_reference_free(branch); +} + +void test_worktree_refs__renaming_reference_updates_worktree_heads(void) +{ + git_reference *head, *branch, *renamed; + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "testrepo-worktree", GIT_BRANCH_LOCAL)); + cl_git_pass(git_reference_rename(&renamed, branch, "refs/heads/renamed", 0, NULL)); + + cl_git_pass(git_reference_lookup(&head, fixture.worktree, GIT_HEAD_FILE)); + cl_assert_equal_i(git_reference_type(head), GIT_REFERENCE_SYMBOLIC); + cl_assert_equal_s(git_reference_symbolic_target(head), "refs/heads/renamed"); + + git_reference_free(head); + git_reference_free(branch); + git_reference_free(renamed); +} + +void test_worktree_refs__creating_refs_uses_commondir(void) +{ + git_reference *head, *branch, *lookup; + git_commit *commit; + git_str refpath = GIT_STR_INIT; + + cl_git_pass(git_str_joinpath(&refpath, + git_repository_commondir(fixture.worktree), "refs/heads/testbranch")); + cl_assert(!git_fs_path_exists(refpath.ptr)); + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + cl_git_pass(git_commit_lookup(&commit, fixture.worktree, git_reference_target(head))); + cl_git_pass(git_branch_create(&branch, fixture.worktree, "testbranch", commit, 0)); + cl_git_pass(git_branch_lookup(&lookup, fixture.worktree, "testbranch", GIT_BRANCH_LOCAL)); + cl_assert(git_reference_cmp(branch, lookup) == 0); + cl_assert(git_fs_path_exists(refpath.ptr)); + + git_reference_free(lookup); + git_reference_free(branch); + git_reference_free(head); + git_commit_free(commit); + git_str_dispose(&refpath); +} diff --git a/tests/libgit2/worktree/repository.c b/tests/libgit2/worktree/repository.c new file mode 100644 index 000000000..c4eeadd35 --- /dev/null +++ b/tests/libgit2/worktree/repository.c @@ -0,0 +1,67 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" +#include "submodule/submodule_helpers.h" + +#include "repository.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_repository__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_repository__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_repository__head(void) +{ + git_reference *ref, *head; + + cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree")); + cl_git_pass(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree")); + cl_assert(git_reference_cmp(ref, head) == 0); + cl_assert(git_reference_owner(ref) == fixture.repo); + + git_reference_free(ref); + git_reference_free(head); +} + +void test_worktree_repository__head_fails_for_invalid_worktree(void) +{ + git_reference *head = NULL; + + cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "invalid")); + cl_assert(head == NULL); +} + +void test_worktree_repository__head_detached(void) +{ + git_reference *ref, *head; + + cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree")); + cl_git_pass(git_repository_set_head_detached(fixture.worktree, &ref->target.oid)); + + cl_assert(git_repository_head_detached(fixture.worktree)); + cl_assert(git_repository_head_detached_for_worktree(fixture.repo, "testrepo-worktree")); + cl_git_pass(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree")); + + cl_assert_equal_oid(&ref->target.oid, &head->target.oid); + + git_reference_free(ref); + git_reference_free(head); +} + +void test_worktree_repository__head_detached_fails_for_invalid_worktree(void) +{ + git_reference *head = NULL; + + cl_git_fail(git_repository_head_detached_for_worktree(fixture.repo, "invalid")); + cl_assert(head == NULL); +} diff --git a/tests/libgit2/worktree/submodule.c b/tests/libgit2/worktree/submodule.c new file mode 100644 index 000000000..6b0c07452 --- /dev/null +++ b/tests/libgit2/worktree/submodule.c @@ -0,0 +1,92 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "worktree.h" +#include "worktree_helpers.h" + +#define WORKTREE_PARENT "submodules-worktree-parent" +#define WORKTREE_CHILD "submodules-worktree-child" + +static worktree_fixture parent + = WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT); +static worktree_fixture child + = WORKTREE_FIXTURE_INIT(NULL, WORKTREE_CHILD); + +void test_worktree_submodule__initialize(void) +{ + setup_fixture_worktree(&parent); + + cl_git_pass(p_rename( + "submodules/testrepo/.gitted", + "submodules/testrepo/.git")); + + setup_fixture_worktree(&child); +} + +void test_worktree_submodule__cleanup(void) +{ + cleanup_fixture_worktree(&child); + cleanup_fixture_worktree(&parent); +} + +void test_worktree_submodule__submodule_worktree_parent(void) +{ + cl_assert(git_repository_path(parent.worktree) != NULL); + cl_assert(git_repository_workdir(parent.worktree) != NULL); + + cl_assert(!parent.repo->is_worktree); + cl_assert(parent.worktree->is_worktree); +} + +void test_worktree_submodule__submodule_worktree_child(void) +{ + cl_assert(!parent.repo->is_worktree); + cl_assert(parent.worktree->is_worktree); + cl_assert(child.worktree->is_worktree); +} + +void test_worktree_submodule__open_discovered_submodule_worktree(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + + cl_git_pass(git_repository_discover(&path, + git_repository_workdir(child.worktree), false, NULL)); + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert_equal_s(git_repository_workdir(child.worktree), + git_repository_workdir(repo)); + + git_buf_dispose(&path); + git_repository_free(repo); +} + +void test_worktree_submodule__resolve_relative_url(void) +{ + git_str wt_path = GIT_STR_INIT; + git_buf sm_relative_path = GIT_BUF_INIT, wt_relative_path = GIT_BUF_INIT; + git_repository *repo; + git_worktree *wt; + + cl_git_pass(git_futils_mkdir("subdir", 0755, GIT_MKDIR_PATH)); + cl_git_pass(git_fs_path_prettify_dir(&wt_path, "subdir", NULL)); + cl_git_pass(git_str_joinpath(&wt_path, wt_path.ptr, "wt")); + + /* Open child repository, which is a submodule */ + cl_git_pass(git_repository_open(&child.repo, WORKTREE_CHILD)); + + /* Create worktree of submodule repository */ + cl_git_pass(git_worktree_add(&wt, child.repo, "subdir", wt_path.ptr, NULL)); + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + + cl_git_pass(git_submodule_resolve_url(&sm_relative_path, repo, + "../" WORKTREE_CHILD)); + cl_git_pass(git_submodule_resolve_url(&wt_relative_path, child.repo, + "../" WORKTREE_CHILD)); + + cl_assert_equal_s(sm_relative_path.ptr, wt_relative_path.ptr); + + git_worktree_free(wt); + git_repository_free(repo); + git_str_dispose(&wt_path); + git_buf_dispose(&sm_relative_path); + git_buf_dispose(&wt_relative_path); +} diff --git a/tests/libgit2/worktree/worktree.c b/tests/libgit2/worktree/worktree.c new file mode 100644 index 000000000..66273d1cb --- /dev/null +++ b/tests/libgit2/worktree/worktree.c @@ -0,0 +1,647 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" +#include "submodule/submodule_helpers.h" + +#include "checkout.h" +#include "repository.h" +#include "worktree.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_worktree__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_worktree__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_worktree__list(void) +{ + git_strarray wts; + + cl_git_pass(git_worktree_list(&wts, fixture.repo)); + cl_assert_equal_i(wts.count, 1); + cl_assert_equal_s(wts.strings[0], "testrepo-worktree"); + + git_strarray_dispose(&wts); +} + +void test_worktree_worktree__list_with_invalid_worktree_dirs(void) +{ + const char *filesets[3][2] = { + { "gitdir", "commondir" }, + { "gitdir", "HEAD" }, + { "HEAD", "commondir" }, + }; + git_str path = GIT_STR_INIT; + git_strarray wts; + size_t i, j, len; + + cl_git_pass(git_str_joinpath(&path, + fixture.repo->commondir, + "worktrees/invalid")); + cl_git_pass(p_mkdir(path.ptr, 0755)); + + len = path.size; + + for (i = 0; i < ARRAY_SIZE(filesets); i++) { + + for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) { + git_str_truncate(&path, len); + cl_git_pass(git_str_joinpath(&path, path.ptr, filesets[i][j])); + cl_git_pass(p_close(p_creat(path.ptr, 0644))); + } + + cl_git_pass(git_worktree_list(&wts, fixture.worktree)); + cl_assert_equal_i(wts.count, 1); + cl_assert_equal_s(wts.strings[0], "testrepo-worktree"); + git_strarray_dispose(&wts); + + for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) { + git_str_truncate(&path, len); + cl_git_pass(git_str_joinpath(&path, path.ptr, filesets[i][j])); + p_unlink(path.ptr); + } + } + + git_str_dispose(&path); +} + +void test_worktree_worktree__list_in_worktree_repo(void) +{ + git_strarray wts; + + cl_git_pass(git_worktree_list(&wts, fixture.worktree)); + cl_assert_equal_i(wts.count, 1); + cl_assert_equal_s(wts.strings[0], "testrepo-worktree"); + + git_strarray_dispose(&wts); +} + +void test_worktree_worktree__list_without_worktrees(void) +{ + git_repository *repo; + git_strarray wts; + + repo = cl_git_sandbox_init("testrepo2"); + cl_git_pass(git_worktree_list(&wts, repo)); + cl_assert_equal_i(wts.count, 0); + + git_repository_free(repo); +} + +void test_worktree_worktree__lookup(void) +{ + git_worktree *wt; + git_str gitdir_path = GIT_STR_INIT; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_git_pass(git_str_joinpath(&gitdir_path, fixture.repo->commondir, "worktrees/testrepo-worktree/")); + + cl_assert_equal_s(wt->gitdir_path, gitdir_path.ptr); + cl_assert_equal_s(wt->parent_path, fixture.repo->workdir); + cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink); + cl_assert_equal_s(wt->commondir_path, fixture.repo->gitdir); + cl_assert_equal_s(wt->commondir_path, fixture.repo->commondir); + + git_str_dispose(&gitdir_path); + git_worktree_free(wt); +} + +void test_worktree_worktree__lookup_nonexistent_worktree(void) +{ + git_worktree *wt; + + cl_git_fail(git_worktree_lookup(&wt, fixture.repo, "nonexistent")); + cl_assert_equal_p(wt, NULL); +} + +void test_worktree_worktree__open(void) +{ + git_worktree *wt; + git_repository *repo; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + cl_assert_equal_s(git_repository_workdir(repo), + git_repository_workdir(fixture.worktree)); + + git_repository_free(repo); + git_worktree_free(wt); +} + +void test_worktree_worktree__open_invalid_commondir(void) +{ + git_worktree *wt; + git_repository *repo; + git_str buf = GIT_STR_INIT, path = GIT_STR_INIT; + + cl_git_pass(git_str_sets(&buf, "/path/to/nonexistent/commondir")); + cl_git_pass(git_str_joinpath(&path, + fixture.repo->commondir, + "worktrees/testrepo-worktree/commondir")); + cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_str_dispose(&buf); + git_str_dispose(&path); + git_worktree_free(wt); +} + +void test_worktree_worktree__open_invalid_gitdir(void) +{ + git_worktree *wt; + git_repository *repo; + git_str buf = GIT_STR_INIT, path = GIT_STR_INIT; + + cl_git_pass(git_str_sets(&buf, "/path/to/nonexistent/gitdir")); + cl_git_pass(git_str_joinpath(&path, + fixture.repo->commondir, + "worktrees/testrepo-worktree/gitdir")); + cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_str_dispose(&buf); + git_str_dispose(&path); + git_worktree_free(wt); +} + +void test_worktree_worktree__open_invalid_parent(void) +{ + git_worktree *wt; + git_repository *repo; + git_str buf = GIT_STR_INIT; + + cl_git_pass(git_str_sets(&buf, "/path/to/nonexistent/gitdir")); + cl_git_pass(git_futils_writebuffer(&buf, + fixture.worktree->gitlink, O_RDWR, 0644)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_str_dispose(&buf); + git_worktree_free(wt); +} + +void test_worktree_worktree__init(void) +{ + git_worktree *wt; + git_repository *repo; + git_reference *branch; + git_str path = GIT_STR_INIT; + + cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../worktree-new")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + + /* Open and verify created repo */ + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-new/") == 0); + cl_git_pass(git_branch_lookup(&branch, repo, "worktree-new", GIT_BRANCH_LOCAL)); + + git_str_dispose(&path); + git_worktree_free(wt); + git_reference_free(branch); + git_repository_free(repo); +} + +void test_worktree_worktree__add_locked(void) +{ + git_worktree *wt; + git_repository *repo; + git_reference *branch; + git_str path = GIT_STR_INIT; + git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT; + + opts.lock = 1; + + cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../worktree-locked")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-locked", path.ptr, &opts)); + + /* Open and verify created repo */ + cl_assert(git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-locked/") == 0); + cl_git_pass(git_branch_lookup(&branch, repo, "worktree-locked", GIT_BRANCH_LOCAL)); + + git_str_dispose(&path); + git_worktree_free(wt); + git_reference_free(branch); + git_repository_free(repo); +} + +void test_worktree_worktree__init_existing_branch(void) +{ + git_reference *head, *branch; + git_commit *commit; + git_worktree *wt; + git_str path = GIT_STR_INIT; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_pass(git_commit_lookup(&commit, fixture.repo, &head->target.oid)); + cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new", commit, false)); + + cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../worktree-new")); + cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + + git_str_dispose(&path); + git_commit_free(commit); + git_reference_free(head); + git_reference_free(branch); +} + +void test_worktree_worktree__add_with_explicit_branch(void) +{ + git_reference *head, *branch, *wthead; + git_commit *commit; + git_worktree *wt; + git_repository *wtrepo; + git_str path = GIT_STR_INIT; + git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_pass(git_commit_lookup(&commit, fixture.repo, &head->target.oid)); + cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-with-ref", commit, false)); + + opts.ref = branch; + + cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../worktree-with-different-name")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-with-different-name", path.ptr, &opts)); + cl_git_pass(git_repository_open_from_worktree(&wtrepo, wt)); + cl_git_pass(git_repository_head(&wthead, wtrepo)); + cl_assert_equal_s(git_reference_name(wthead), "refs/heads/worktree-with-ref"); + + git_str_dispose(&path); + git_commit_free(commit); + git_reference_free(head); + git_reference_free(branch); + git_reference_free(wthead); + git_repository_free(wtrepo); + git_worktree_free(wt); +} + +void test_worktree_worktree__add_no_checkout(void) +{ + git_worktree *wt; + git_repository *wtrepo; + git_index *index; + git_str path = GIT_STR_INIT; + git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT; + + opts.checkout_options.checkout_strategy = GIT_CHECKOUT_NONE; + + cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../worktree-no-checkout")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-no-checkout", path.ptr, &opts)); + + cl_git_pass(git_repository_open(&wtrepo, path.ptr)); + cl_git_pass(git_repository_index(&index, wtrepo)); + cl_assert_equal_i(git_index_entrycount(index), 0); + + git_str_dispose(&path); + git_worktree_free(wt); + git_index_free(index); + git_repository_free(wtrepo); +} + +void test_worktree_worktree__init_existing_worktree(void) +{ + git_worktree *wt; + git_str path = GIT_STR_INIT; + + cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../worktree-new")); + cl_git_fail(git_worktree_add(&wt, fixture.repo, "testrepo-worktree", path.ptr, NULL)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink); + + git_str_dispose(&path); + git_worktree_free(wt); +} + +void test_worktree_worktree__init_existing_path(void) +{ + const char *wtfiles[] = { "HEAD", "commondir", "gitdir", "index" }; + git_worktree *wt; + git_str path = GIT_STR_INIT; + unsigned i; + + /* Delete files to verify they have not been created by + * the init call */ + for (i = 0; i < ARRAY_SIZE(wtfiles); i++) { + cl_git_pass(git_str_joinpath(&path, + fixture.worktree->gitdir, wtfiles[i])); + cl_git_pass(p_unlink(path.ptr)); + } + + cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../testrepo-worktree")); + cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + + /* Verify files have not been re-created */ + for (i = 0; i < ARRAY_SIZE(wtfiles); i++) { + cl_git_pass(git_str_joinpath(&path, + fixture.worktree->gitdir, wtfiles[i])); + cl_assert(!git_fs_path_exists(path.ptr)); + } + + git_str_dispose(&path); +} + +void test_worktree_worktree__init_submodule(void) +{ + git_repository *repo, *sm, *wt; + git_worktree *worktree; + git_str path = GIT_STR_INIT; + + cleanup_fixture_worktree(&fixture); + repo = setup_fixture_submod2(); + + cl_git_pass(git_str_joinpath(&path, repo->workdir, "sm_unchanged")); + cl_git_pass(git_repository_open(&sm, path.ptr)); + cl_git_pass(git_str_joinpath(&path, repo->workdir, "../worktree/")); + cl_git_pass(git_worktree_add(&worktree, sm, "repo-worktree", path.ptr, NULL)); + cl_git_pass(git_repository_open_from_worktree(&wt, worktree)); + + cl_git_pass(git_fs_path_prettify_dir(&path, path.ptr, NULL)); + cl_assert_equal_s(path.ptr, wt->workdir); + cl_git_pass(git_fs_path_prettify_dir(&path, sm->commondir, NULL)); + cl_assert_equal_s(sm->commondir, wt->commondir); + + cl_git_pass(git_str_joinpath(&path, sm->gitdir, "worktrees/repo-worktree/")); + cl_assert_equal_s(path.ptr, wt->gitdir); + + git_str_dispose(&path); + git_worktree_free(worktree); + git_repository_free(sm); + git_repository_free(wt); +} + +void test_worktree_worktree__validate(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_validate(wt)); + + git_worktree_free(wt); +} + +void test_worktree_worktree__name(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_assert_equal_s(git_worktree_name(wt), "testrepo-worktree"); + + git_worktree_free(wt); +} + +void test_worktree_worktree__path(void) +{ + git_worktree *wt; + git_str expected_path = GIT_STR_INIT; + + cl_git_pass(git_str_joinpath(&expected_path, clar_sandbox_path(), "testrepo-worktree")); + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_assert_equal_s(git_worktree_path(wt), expected_path.ptr); + + git_str_dispose(&expected_path); + git_worktree_free(wt); +} + +void test_worktree_worktree__validate_invalid_commondir(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + git__free(wt->commondir_path); + wt->commondir_path = "/path/to/invalid/commondir"; + + cl_git_fail(git_worktree_validate(wt)); + + wt->commondir_path = NULL; + git_worktree_free(wt); +} + +void test_worktree_worktree__validate_invalid_gitdir(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + git__free(wt->gitdir_path); + wt->gitdir_path = "/path/to/invalid/gitdir"; + cl_git_fail(git_worktree_validate(wt)); + + wt->gitdir_path = NULL; + git_worktree_free(wt); +} + +void test_worktree_worktree__validate_invalid_parent(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + git__free(wt->parent_path); + wt->parent_path = "/path/to/invalid/parent"; + cl_git_fail(git_worktree_validate(wt)); + + wt->parent_path = NULL; + git_worktree_free(wt); +} + +void test_worktree_worktree__lock_with_reason(void) +{ + git_worktree *wt; + git_buf reason = GIT_BUF_INIT; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_assert(!git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_worktree_lock(wt, "because")); + cl_assert(git_worktree_is_locked(&reason, wt) > 0); + cl_assert_equal_s(reason.ptr, "because"); + cl_assert(wt->locked); + + git_buf_dispose(&reason); + git_worktree_free(wt); +} + +void test_worktree_worktree__lock_without_reason(void) +{ + git_worktree *wt; + git_buf reason = GIT_BUF_INIT; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_assert(!git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_worktree_lock(wt, NULL)); + cl_assert(git_worktree_is_locked(&reason, wt) > 0); + cl_assert_equal_i(reason.size, 0); + cl_assert(wt->locked); + + git_buf_dispose(&reason); + git_worktree_free(wt); +} + +void test_worktree_worktree__unlock_unlocked_worktree(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_assert(!git_worktree_is_locked(NULL, wt)); + cl_assert_equal_i(1, git_worktree_unlock(wt)); + cl_assert(!wt->locked); + + git_worktree_free(wt); +} + +void test_worktree_worktree__unlock_locked_worktree(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_lock(wt, NULL)); + cl_assert(git_worktree_is_locked(NULL, wt)); + cl_assert_equal_i(0, git_worktree_unlock(wt)); + cl_assert(!wt->locked); + + git_worktree_free(wt); +} + +void test_worktree_worktree__prune_without_opts_fails(void) +{ + git_worktree *wt; + git_repository *repo; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_worktree_prune(wt, NULL)); + + /* Assert the repository is still valid */ + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + + git_worktree_free(wt); + git_repository_free(repo); +} + +void test_worktree_worktree__prune_valid(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + git_repository *repo; + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_prune(wt, &opts)); + + /* Assert the repository is not valid anymore */ + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_worktree_free(wt); + git_repository_free(repo); +} + +void test_worktree_worktree__prune_locked(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + git_repository *repo; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_lock(wt, NULL)); + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + cl_git_fail(git_worktree_prune(wt, &opts)); + /* Assert the repository is still valid */ + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + + opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_LOCKED; + cl_git_pass(git_worktree_prune(wt, &opts)); + + git_worktree_free(wt); + git_repository_free(repo); +} + +void test_worktree_worktree__prune_gitdir_only(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_prune(wt, &opts)); + + cl_assert(!git_fs_path_exists(wt->gitdir_path)); + cl_assert(git_fs_path_exists(wt->gitlink_path)); + + git_worktree_free(wt); +} + +void test_worktree_worktree__prune_worktree(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + + opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_WORKING_TREE; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_prune(wt, &opts)); + + cl_assert(!git_fs_path_exists(wt->gitdir_path)); + cl_assert(!git_fs_path_exists(wt->gitlink_path)); + + git_worktree_free(wt); +} + +static int foreach_worktree_cb(git_repository *worktree, void *payload) +{ + int *counter = (int *)payload; + + switch (*counter) { + case 0: + cl_assert_equal_s(git_repository_path(fixture.repo), + git_repository_path(worktree)); + cl_assert(!git_repository_is_worktree(worktree)); + break; + case 1: + cl_assert_equal_s(git_repository_path(fixture.worktree), + git_repository_path(worktree)); + cl_assert(git_repository_is_worktree(worktree)); + break; + default: + cl_fail("more worktrees found than expected"); + } + + (*counter)++; + + return 0; +} + +void test_worktree_worktree__foreach_worktree_lists_all_worktrees(void) +{ + int counter = 0; + cl_git_pass(git_repository_foreach_worktree(fixture.repo, foreach_worktree_cb, &counter)); +} + +void test_worktree_worktree__validate_invalid_worktreedir(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + p_rename("testrepo-worktree", "testrepo-worktree-tmp"); + cl_git_fail(git_worktree_validate(wt)); + p_rename("testrepo-worktree-tmp", "testrepo-worktree"); + + git_worktree_free(wt); +} diff --git a/tests/libgit2/worktree/worktree_helpers.c b/tests/libgit2/worktree/worktree_helpers.c new file mode 100644 index 000000000..6d4cdbaeb --- /dev/null +++ b/tests/libgit2/worktree/worktree_helpers.c @@ -0,0 +1,30 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" + +void cleanup_fixture_worktree(worktree_fixture *fixture) +{ + if (!fixture) + return; + + if (fixture->repo) { + git_repository_free(fixture->repo); + fixture->repo = NULL; + } + if (fixture->worktree) { + git_repository_free(fixture->worktree); + fixture->worktree = NULL; + } + + if (fixture->reponame) + cl_fixture_cleanup(fixture->reponame); + if (fixture->worktreename) + cl_fixture_cleanup(fixture->worktreename); +} + +void setup_fixture_worktree(worktree_fixture *fixture) +{ + if (fixture->reponame) + fixture->repo = cl_git_sandbox_init(fixture->reponame); + if (fixture->worktreename) + fixture->worktree = cl_git_sandbox_init(fixture->worktreename); +} diff --git a/tests/libgit2/worktree/worktree_helpers.h b/tests/libgit2/worktree/worktree_helpers.h new file mode 100644 index 000000000..35ea9ed4c --- /dev/null +++ b/tests/libgit2/worktree/worktree_helpers.h @@ -0,0 +1,11 @@ +typedef struct { + const char *reponame; + const char *worktreename; + git_repository *repo; + git_repository *worktree; +} worktree_fixture; + +#define WORKTREE_FIXTURE_INIT(repo, worktree) { (repo), (worktree), NULL, NULL } + +void cleanup_fixture_worktree(worktree_fixture *fixture); +void setup_fixture_worktree(worktree_fixture *fixture); |
