Initial commit - full huishou project

This commit is contained in:
jiapengyu
2026-07-27 14:07:26 +08:00
commit 60790ad1b3
39127 changed files with 5989265 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "refs.h"
#include "ref_helpers.h"
static git_repository *g_repo;
static const char *loose_tag_ref_name = "refs/tags/e90810b";
void test_refs_basic__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_repository_set_ident(g_repo, "me", "foo@example.com"));
}
void test_refs_basic__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_basic__reference_realloc(void)
{
git_reference *ref;
git_reference *new_ref;
const char *new_name = "refs/tags/awful/name-which-is/clearly/really-that-much/longer-than/the-old-one";
/* Retrieval of the reference to rename */
cl_git_pass(git_reference_lookup(&ref, g_repo, loose_tag_ref_name));
new_ref = git_reference__realloc(&ref, new_name);
cl_assert(new_ref != NULL);
git_reference_free(new_ref);
git_reference_free(ref);
/* Reload, so we restore the value */
cl_git_pass(git_reference_lookup(&ref, g_repo, loose_tag_ref_name));
cl_git_pass(git_reference_rename(&new_ref, ref, new_name, 1, "log message"));
cl_assert(ref != NULL);
cl_assert(new_ref != NULL);
git_reference_free(new_ref);
git_reference_free(ref);
}
+53
View File
@@ -0,0 +1,53 @@
#include "clar_libgit2.h"
#include "refs.h"
#include "worktree/worktree_helpers.h"
static git_repository *repo;
static void assert_checked_out(git_repository *repo, const char *branch, int checked_out)
{
git_reference *ref;
cl_git_pass(git_reference_lookup(&ref, repo, branch));
cl_assert(git_branch_is_checked_out(ref) == checked_out);
git_reference_free(ref);
}
void test_refs_branches_checkedout__simple_repo(void)
{
repo = cl_git_sandbox_init("testrepo");
assert_checked_out(repo, "refs/heads/master", 1);
assert_checked_out(repo, "refs/heads/executable", 0);
cl_git_sandbox_cleanup();
}
void test_refs_branches_checkedout__worktree(void)
{
static worktree_fixture fixture =
WORKTREE_FIXTURE_INIT("testrepo", "testrepo-worktree");
setup_fixture_worktree(&fixture);
assert_checked_out(fixture.repo, "refs/heads/master", 1);
assert_checked_out(fixture.repo, "refs/heads/testrepo-worktree", 1);
assert_checked_out(fixture.worktree, "refs/heads/master", 1);
assert_checked_out(fixture.worktree, "refs/heads/testrepo-worktree", 1);
cleanup_fixture_worktree(&fixture);
}
void test_refs_branches_checkedout__head_is_not_checked_out(void)
{
repo = cl_git_sandbox_init("testrepo");
assert_checked_out(repo, "HEAD", 0);
cl_git_sandbox_cleanup();
}
void test_refs_branches_checkedout__master_in_bare_repo_is_not_checked_out(void)
{
repo = cl_git_sandbox_init("testrepo.git");
assert_checked_out(repo, "refs/heads/master", 0);
cl_git_sandbox_cleanup();
}
+279
View File
@@ -0,0 +1,279 @@
#include "clar_libgit2.h"
#include "refs.h"
#include "path.h"
static git_repository *repo;
static git_commit *target;
static git_reference *branch;
void test_refs_branches_create__initialize(void)
{
repo = cl_git_sandbox_init("testrepo.git");
branch = NULL;
target = NULL;
}
void test_refs_branches_create__cleanup(void)
{
git_reference_free(branch);
branch = NULL;
git_commit_free(target);
target = NULL;
cl_git_sandbox_cleanup();
repo = NULL;
}
static void retrieve_target_from_oid(git_commit **out, git_repository *repo, const char *sha)
{
git_object *obj;
cl_git_pass(git_revparse_single(&obj, repo, sha));
cl_git_pass(git_commit_lookup(out, repo, git_object_id(obj)));
git_object_free(obj);
}
static void retrieve_known_commit(git_commit **commit, git_repository *repo)
{
retrieve_target_from_oid(commit, repo, "e90810b8df3");
}
#define NEW_BRANCH_NAME "new-branch-on-the-block"
void test_refs_branches_create__can_create_a_local_branch(void)
{
retrieve_known_commit(&target, repo);
cl_git_pass(git_branch_create(&branch, repo, NEW_BRANCH_NAME, target, 0));
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
}
void test_refs_branches_create__can_not_create_a_branch_if_its_name_collide_with_an_existing_one(void)
{
retrieve_known_commit(&target, repo);
cl_assert_equal_i(GIT_EEXISTS, git_branch_create(&branch, repo, "br2", target, 0));
}
void test_refs_branches_create__can_force_create_over_an_existing_branch(void)
{
retrieve_known_commit(&target, repo);
cl_git_pass(git_branch_create(&branch, repo, "br2", target, 1));
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
cl_assert_equal_s("refs/heads/br2", git_reference_name(branch));
}
void test_refs_branches_create__cannot_force_create_over_current_branch_in_nonbare_repo(void)
{
const git_oid *oid;
git_reference *branch2;
/* Default repo for these tests is a bare repo, but this test requires a non-bare one */
cl_git_sandbox_cleanup();
repo = cl_git_sandbox_init("testrepo");
retrieve_known_commit(&target, repo);
cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL));
cl_assert_equal_s("refs/heads/master", git_reference_name(branch2));
cl_assert_equal_i(true, git_branch_is_head(branch2));
oid = git_reference_target(branch2);
cl_git_fail_with(-1, git_branch_create(&branch, repo, "master", target, 1));
branch = NULL;
cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
cl_assert_equal_s("refs/heads/master", git_reference_name(branch));
cl_git_pass(git_oid_cmp(git_reference_target(branch), oid));
git_reference_free(branch2);
}
void test_refs_branches_create__can_force_create_over_current_branch_in_bare_repo(void)
{
const git_oid *oid;
git_reference *branch2;
retrieve_known_commit(&target, repo);
cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL));
cl_assert_equal_s("refs/heads/master", git_reference_name(branch2));
cl_assert_equal_i(true, git_branch_is_head(branch2));
oid = git_commit_id(target);
cl_git_pass(git_branch_create(&branch, repo, "master", target, 1));
git_reference_free(branch);
branch = NULL;
cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
cl_assert_equal_s("refs/heads/master", git_reference_name(branch));
cl_git_pass(git_oid_cmp(git_reference_target(branch), oid));
git_reference_free(branch2);
}
void test_refs_branches_create__creating_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
retrieve_known_commit(&target, repo);
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_branch_create(&branch, repo, "inv@{id", target, 0));
}
static void assert_branch_matches_name(
const char *expected, const char *lookup_as)
{
git_reference *ref;
git_buf b = GIT_BUF_INIT;
cl_git_pass(git_branch_lookup(&ref, repo, lookup_as, GIT_BRANCH_LOCAL));
cl_git_pass(git_buf_sets(&b, "refs/heads/"));
cl_git_pass(git_buf_puts(&b, expected));
cl_assert_equal_s(b.ptr, git_reference_name(ref));
cl_git_pass(
git_oid_cmp(git_reference_target(ref), git_commit_id(target)));
git_reference_free(ref);
git_buf_dispose(&b);
}
void test_refs_branches_create__can_create_branch_with_unicode(void)
{
const char *nfc = "\xC3\x85\x73\x74\x72\xC3\xB6\x6D";
const char *nfd = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D";
const char *emoji = "\xF0\x9F\x8D\xB7";
const char *names[] = { nfc, nfd, emoji };
const char *alt[] = { nfd, nfc, NULL };
const char *expected[] = { nfc, nfd, emoji };
unsigned int i;
bool fs_decompose_unicode =
git_path_does_fs_decompose_unicode(git_repository_path(repo));
retrieve_known_commit(&target, repo);
if (cl_repo_get_bool(repo, "core.precomposeunicode"))
expected[1] = nfc;
/* test decomp. because not all Mac filesystems decompose unicode */
else if (fs_decompose_unicode)
expected[0] = nfd;
for (i = 0; i < ARRAY_SIZE(names); ++i) {
const char *name;
cl_git_pass(git_branch_create(
&branch, repo, names[i], target, 0));
cl_git_pass(git_oid_cmp(
git_reference_target(branch), git_commit_id(target)));
cl_git_pass(git_branch_name(&name, branch));
cl_assert_equal_s(expected[i], name);
assert_branch_matches_name(expected[i], names[i]);
if (fs_decompose_unicode && alt[i])
assert_branch_matches_name(expected[i], alt[i]);
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
branch = NULL;
}
}
/**
* Verify that we can create a branch with a name that matches the
* namespace of a previously delete branch.
*
* git branch level_one/level_two
* git branch -D level_one/level_two
* git branch level_one
*
* We expect the delete to have deleted the files:
* ".git/refs/heads/level_one/level_two"
* ".git/logs/refs/heads/level_one/level_two"
* It may or may not have deleted the (now empty)
* containing directories. To match git.git behavior,
* the second create needs to implicilty delete the
* directories and create the new files.
* "refs/heads/level_one"
* "logs/refs/heads/level_one"
*
* We should not fail to create the branch or its
* reflog because of an obsolete namespace container
* directory.
*/
void test_refs_branches_create__name_vs_namespace(void)
{
const char * name;
struct item {
const char *first;
const char *second;
};
static const struct item item[] = {
{ "level_one/level_two", "level_one" },
{ "a/b/c/d/e", "a/b/c/d" },
{ "ss/tt/uu/vv/ww", "ss" },
/* And one test case that is deeper. */
{ "xx1/xx2/xx3/xx4", "xx1/xx2/xx3/xx4/xx5/xx6" },
{ NULL, NULL },
};
const struct item *p;
retrieve_known_commit(&target, repo);
for (p=item; p->first; p++) {
cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0));
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
cl_git_pass(git_branch_name(&name, branch));
cl_assert_equal_s(name, p->first);
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
branch = NULL;
cl_git_pass(git_branch_create(&branch, repo, p->second, target, 0));
git_reference_free(branch);
branch = NULL;
}
}
/**
* We still need to fail if part of the namespace is
* still in use.
*/
void test_refs_branches_create__name_vs_namespace_fail(void)
{
const char * name;
struct item {
const char *first;
const char *first_alternate;
const char *second;
};
static const struct item item[] = {
{ "level_one/level_two", "level_one/alternate", "level_one" },
{ "a/b/c/d/e", "a/b/c/d/alternate", "a/b/c/d" },
{ "ss/tt/uu/vv/ww", "ss/alternate", "ss" },
{ NULL, NULL, NULL },
};
const struct item *p;
retrieve_known_commit(&target, repo);
for (p=item; p->first; p++) {
cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0));
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
cl_git_pass(git_branch_name(&name, branch));
cl_assert_equal_s(name, p->first);
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
branch = NULL;
cl_git_pass(git_branch_create(&branch, repo, p->first_alternate, target, 0));
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
cl_git_pass(git_branch_name(&name, branch));
cl_assert_equal_s(name, p->first_alternate);
/* we do not delete the alternate. */
git_reference_free(branch);
branch = NULL;
cl_git_fail(git_branch_create(&branch, repo, p->second, target, 0));
git_reference_free(branch);
branch = NULL;
}
}
+188
View File
@@ -0,0 +1,188 @@
#include "clar_libgit2.h"
#include "refs.h"
#include "repo/repo_helpers.h"
#include "config/config_helpers.h"
#include "futils.h"
#include "reflog.h"
static git_repository *repo;
static git_reference *fake_remote;
void test_refs_branches_delete__initialize(void)
{
git_oid id;
repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0, NULL));
}
void test_refs_branches_delete__cleanup(void)
{
git_reference_free(fake_remote);
fake_remote = NULL;
cl_git_sandbox_cleanup();
repo = NULL;
}
void test_refs_branches_delete__can_not_delete_a_branch_pointed_at_by_HEAD(void)
{
git_reference *head;
git_reference *branch;
/* Ensure HEAD targets the local master branch */
cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));
git_reference_free(head);
cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
cl_git_fail(git_branch_delete(branch));
git_reference_free(branch);
}
void test_refs_branches_delete__can_delete_a_branch_even_if_HEAD_is_missing(void)
{
git_reference *head;
git_reference *branch;
cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
git_reference_delete(head);
git_reference_free(head);
cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
}
void test_refs_branches_delete__can_delete_a_branch_when_HEAD_is_unborn(void)
{
git_reference *branch;
make_head_unborn(repo, NON_EXISTING_HEAD);
cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
}
void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD(void)
{
git_reference *head, *branch;
cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head));
cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));
git_reference_free(head);
/* Detach HEAD and make it target the commit that "master" points to */
git_repository_detach_head(repo);
cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
}
void test_refs_branches_delete__can_delete_a_local_branch(void)
{
git_reference *branch;
cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
}
void test_refs_branches_delete__can_delete_a_remote_branch(void)
{
git_reference *branch;
cl_git_pass(git_branch_lookup(&branch, repo, "nulltoken/master", GIT_BRANCH_REMOTE));
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
}
void test_refs_branches_delete__deleting_a_branch_removes_related_configuration_data(void)
{
git_reference *branch;
assert_config_entry_existence(repo, "branch.track-local.remote", true);
assert_config_entry_existence(repo, "branch.track-local.merge", true);
cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
assert_config_entry_existence(repo, "branch.track-local.remote", false);
assert_config_entry_existence(repo, "branch.track-local.merge", false);
}
void test_refs_branches_delete__removes_reflog(void)
{
git_reference *branch;
git_reflog *log;
git_oid oidzero = {{0}};
git_signature *sig;
/* Ensure the reflog has at least one entry */
cl_git_pass(git_signature_now(&sig, "Me", "user@example.com"));
cl_git_pass(git_reflog_read(&log, repo, "refs/heads/track-local"));
cl_git_pass(git_reflog_append(log, &oidzero, sig, "message"));
cl_assert(git_reflog_entrycount(log) > 0);
git_signature_free(sig);
git_reflog_free(log);
cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
cl_assert_equal_i(false, git_reference_has_log(repo, "refs/heads/track-local"));
/* Reading a nonexistant reflog creates it, but it should be empty */
cl_git_pass(git_reflog_read(&log, repo, "refs/heads/track-local"));
cl_assert_equal_i(0, git_reflog_entrycount(log));
git_reflog_free(log);
}
void test_refs_branches_delete__removes_empty_folders(void)
{
const char *commondir = git_repository_commondir(repo);
git_oid commit_id;
git_commit *commit;
git_reference *branch;
git_reflog *log;
git_oid oidzero = {{0}};
git_signature *sig;
git_buf ref_folder = GIT_BUF_INIT;
git_buf reflog_folder = GIT_BUF_INIT;
/* Create a new branch with a nested name */
cl_git_pass(git_oid_fromstr(&commit_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"));
cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
cl_git_pass(git_branch_create(&branch, repo, "some/deep/ref", commit, 0));
git_commit_free(commit);
/* Ensure the reflog has at least one entry */
cl_git_pass(git_signature_now(&sig, "Me", "user@example.com"));
cl_git_pass(git_reflog_read(&log, repo, "refs/heads/some/deep/ref"));
cl_git_pass(git_reflog_append(log, &oidzero, sig, "message"));
cl_assert(git_reflog_entrycount(log) > 0);
git_signature_free(sig);
git_reflog_free(log);
cl_git_pass(git_buf_joinpath(&ref_folder, commondir, "refs/heads/some/deep"));
cl_git_pass(git_buf_join3(&reflog_folder, '/', commondir, GIT_REFLOG_DIR, "refs/heads/some/deep"));
cl_assert(git_path_exists(git_buf_cstr(&ref_folder)) == true);
cl_assert(git_path_exists(git_buf_cstr(&reflog_folder)) == true);
cl_git_pass(git_branch_delete(branch));
cl_assert(git_path_exists(git_buf_cstr(&ref_folder)) == false);
cl_assert(git_path_exists(git_buf_cstr(&reflog_folder)) == false);
git_reference_free(branch);
git_buf_dispose(&ref_folder);
git_buf_dispose(&reflog_folder);
}
+98
View File
@@ -0,0 +1,98 @@
#include "clar_libgit2.h"
#include "refs.h"
#include "repo/repo_helpers.h"
static git_repository *repo;
static git_reference *branch;
void test_refs_branches_ishead__initialize(void)
{
repo = cl_git_sandbox_init("testrepo.git");
branch = NULL;
}
void test_refs_branches_ishead__cleanup(void)
{
git_reference_free(branch);
branch = NULL;
cl_git_sandbox_cleanup();
repo = NULL;
}
void test_refs_branches_ishead__can_tell_if_a_branch_is_pointed_at_by_HEAD(void)
{
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
cl_assert_equal_i(true, git_branch_is_head(branch));
}
void test_refs_branches_ishead__can_properly_handle_unborn_HEAD(void)
{
make_head_unborn(repo, NON_EXISTING_HEAD);
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
cl_assert_equal_i(false, git_branch_is_head(branch));
}
void test_refs_branches_ishead__can_properly_handle_missing_HEAD(void)
{
delete_head(repo);
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
cl_assert_equal_i(false, git_branch_is_head(branch));
}
void test_refs_branches_ishead__can_tell_if_a_branch_is_not_pointed_at_by_HEAD(void)
{
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/br2"));
cl_assert_equal_i(false, git_branch_is_head(branch));
}
void test_refs_branches_ishead__wont_be_fooled_by_a_non_branch(void)
{
cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b"));
cl_assert_equal_i(false, git_branch_is_head(branch));
}
/*
* $ git init .
* Initialized empty Git repository in d:/temp/tempee/.git/
*
* $ touch a && git add a
* $ git commit -m" boom"
* [master (root-commit) b47b758] boom
* 0 files changed
* create mode 100644 a
*
* $ echo "ref: refs/heads/master" > .git/refs/heads/linked
* $ echo "ref: refs/heads/linked" > .git/refs/heads/super
* $ echo "ref: refs/heads/super" > .git/HEAD
*
* $ git branch
* linked -> master
* * master
* super -> master
*/
void test_refs_branches_ishead__only_direct_references_are_considered(void)
{
git_reference *linked, *super, *head;
cl_git_pass(git_reference_symbolic_create(&linked, repo, "refs/heads/linked", "refs/heads/master", 0, NULL));
cl_git_pass(git_reference_symbolic_create(&super, repo, "refs/heads/super", "refs/heads/linked", 0, NULL));
cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, "refs/heads/super", 1, NULL));
cl_assert_equal_i(false, git_branch_is_head(linked));
cl_assert_equal_i(false, git_branch_is_head(super));
cl_git_pass(git_repository_head(&branch, repo));
cl_assert_equal_s("refs/heads/master", git_reference_name(branch));
git_reference_free(linked);
git_reference_free(super);
git_reference_free(head);
}
+151
View File
@@ -0,0 +1,151 @@
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *repo;
static git_reference *fake_remote;
void test_refs_branches_iterator__initialize(void)
{
git_oid id;
cl_fixture_sandbox("testrepo.git");
cl_git_pass(git_repository_open(&repo, "testrepo.git"));
cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0, NULL));
}
void test_refs_branches_iterator__cleanup(void)
{
git_reference_free(fake_remote);
fake_remote = NULL;
git_repository_free(repo);
repo = NULL;
cl_fixture_cleanup("testrepo.git");
cl_git_sandbox_cleanup();
}
static void assert_retrieval(unsigned int flags, unsigned int expected_count)
{
git_branch_iterator *iter;
git_reference *ref;
int count = 0, error;
git_branch_t type;
cl_git_pass(git_branch_iterator_new(&iter, repo, flags));
while ((error = git_branch_next(&ref, &type, iter)) == 0) {
count++;
git_reference_free(ref);
}
git_branch_iterator_free(iter);
cl_assert_equal_i(error, GIT_ITEROVER);
cl_assert_equal_i(expected_count, count);
}
void test_refs_branches_iterator__retrieve_all_branches(void)
{
assert_retrieval(GIT_BRANCH_ALL, 14);
}
void test_refs_branches_iterator__retrieve_remote_branches(void)
{
assert_retrieval(GIT_BRANCH_REMOTE, 2);
}
void test_refs_branches_iterator__retrieve_local_branches(void)
{
assert_retrieval(GIT_BRANCH_LOCAL, 12);
}
struct expectations {
const char *branch_name;
int encounters;
};
static void assert_branch_has_been_found(struct expectations *findings, const char* expected_branch_name)
{
int pos = 0;
for (pos = 0; findings[pos].branch_name; ++pos) {
if (strcmp(expected_branch_name, findings[pos].branch_name) == 0) {
cl_assert_equal_i(1, findings[pos].encounters);
return;
}
}
cl_fail("expected branch not found in list.");
}
static void contains_branches(struct expectations exp[], git_branch_iterator *iter)
{
git_reference *ref;
git_branch_t type;
int error, pos = 0;
while ((error = git_branch_next(&ref, &type, iter)) == 0) {
for (pos = 0; exp[pos].branch_name; ++pos) {
if (strcmp(git_reference_shorthand(ref), exp[pos].branch_name) == 0)
exp[pos].encounters++;
}
git_reference_free(ref);
}
cl_assert_equal_i(error, GIT_ITEROVER);
}
/*
* $ git branch -r
* nulltoken/HEAD -> nulltoken/master
* nulltoken/master
*/
void test_refs_branches_iterator__retrieve_remote_symbolic_HEAD_when_present(void)
{
git_branch_iterator *iter;
struct expectations exp[] = {
{ "nulltoken/HEAD", 0 },
{ "nulltoken/master", 0 },
{ NULL, 0 }
};
git_reference_free(fake_remote);
cl_git_pass(git_reference_symbolic_create(&fake_remote, repo, "refs/remotes/nulltoken/HEAD", "refs/remotes/nulltoken/master", 0, NULL));
assert_retrieval(GIT_BRANCH_REMOTE, 3);
cl_git_pass(git_branch_iterator_new(&iter, repo, GIT_BRANCH_REMOTE));
contains_branches(exp, iter);
git_branch_iterator_free(iter);
assert_branch_has_been_found(exp, "nulltoken/HEAD");
assert_branch_has_been_found(exp, "nulltoken/master");
}
void test_refs_branches_iterator__mix_of_packed_and_loose(void)
{
git_branch_iterator *iter;
struct expectations exp[] = {
{ "master", 0 },
{ "origin/HEAD", 0 },
{ "origin/master", 0 },
{ "origin/packed", 0 },
{ NULL, 0 }
};
git_repository *r2;
r2 = cl_git_sandbox_init("testrepo2");
cl_git_pass(git_branch_iterator_new(&iter, r2, GIT_BRANCH_ALL));
contains_branches(exp, iter);
git_branch_iterator_free(iter);
assert_branch_has_been_found(exp, "master");
assert_branch_has_been_found(exp, "origin/HEAD");
assert_branch_has_been_found(exp, "origin/master");
assert_branch_has_been_found(exp, "origin/packed");
}
+68
View File
@@ -0,0 +1,68 @@
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *repo;
static git_reference *branch;
void test_refs_branches_lookup__initialize(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
branch = NULL;
}
void test_refs_branches_lookup__cleanup(void)
{
git_reference_free(branch);
branch = NULL;
git_repository_free(repo);
repo = NULL;
}
void test_refs_branches_lookup__can_retrieve_a_local_branch_local(void)
{
cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
}
void test_refs_branches_lookup__can_retrieve_a_local_branch_all(void)
{
cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_ALL));
}
void test_refs_branches_lookup__trying_to_retrieve_a_local_branch_remote(void)
{
cl_git_fail(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_REMOTE));
}
void test_refs_branches_lookup__can_retrieve_a_remote_tracking_branch_remote(void)
{
cl_git_pass(git_branch_lookup(&branch, repo, "test/master", GIT_BRANCH_REMOTE));
}
void test_refs_branches_lookup__can_retrieve_a_remote_tracking_branch_all(void)
{
cl_git_pass(git_branch_lookup(&branch, repo, "test/master", GIT_BRANCH_ALL));
}
void test_refs_branches_lookup__trying_to_retrieve_a_remote_tracking_branch_local(void)
{
cl_git_fail(git_branch_lookup(&branch, repo, "test/master", GIT_BRANCH_LOCAL));
}
void test_refs_branches_lookup__trying_to_retrieve_an_unknown_branch_returns_ENOTFOUND(void)
{
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "where/are/you", GIT_BRANCH_LOCAL));
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "over/here", GIT_BRANCH_REMOTE));
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "maybe/here", GIT_BRANCH_ALL));
}
void test_refs_branches_lookup__trying_to_retrieve_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_branch_lookup(&branch, repo, "are/you/inv@{id", GIT_BRANCH_LOCAL));
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_branch_lookup(&branch, repo, "yes/i am", GIT_BRANCH_REMOTE));
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_branch_lookup(&branch, repo, "inv al/id", GIT_BRANCH_ALL));
}
+213
View File
@@ -0,0 +1,213 @@
#include "clar_libgit2.h"
#include "refs.h"
#include "config/config_helpers.h"
static git_repository *repo;
void test_refs_branches_move__initialize(void)
{
repo = cl_git_sandbox_init("testrepo.git");
}
void test_refs_branches_move__cleanup(void)
{
cl_git_sandbox_cleanup();
}
#define NEW_BRANCH_NAME "new-branch-on-the-block"
void test_refs_branches_move__can_move_a_local_branch(void)
{
git_reference *original_ref, *new_ref;
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
cl_git_pass(git_branch_move(&new_ref, original_ref, NEW_BRANCH_NAME, 0));
cl_assert_equal_s(GIT_REFS_HEADS_DIR NEW_BRANCH_NAME, git_reference_name(new_ref));
git_reference_free(original_ref);
git_reference_free(new_ref);
}
void test_refs_branches_move__can_move_a_local_branch_to_a_different_namespace(void)
{
git_reference *original_ref, *new_ref, *newer_ref;
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
/* Downward */
cl_git_pass(git_branch_move(&new_ref, original_ref, "somewhere/" NEW_BRANCH_NAME, 0));
git_reference_free(original_ref);
/* Upward */
cl_git_pass(git_branch_move(&newer_ref, new_ref, "br2", 0));
git_reference_free(new_ref);
git_reference_free(newer_ref);
}
void test_refs_branches_move__can_move_a_local_branch_to_a_partially_colliding_namespace(void)
{
git_reference *original_ref, *new_ref, *newer_ref;
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
/* Downward */
cl_git_pass(git_branch_move(&new_ref, original_ref, "br2/" NEW_BRANCH_NAME, 0));
git_reference_free(original_ref);
/* Upward */
cl_git_pass(git_branch_move(&newer_ref, new_ref, "br2", 0));
git_reference_free(new_ref);
git_reference_free(newer_ref);
}
void test_refs_branches_move__can_not_move_a_branch_if_its_destination_name_collide_with_an_existing_one(void)
{
git_reference *original_ref, *new_ref;
git_config *config;
git_buf buf = GIT_BUF_INIT;
char *original_remote, *original_merge;
const char *str;
cl_git_pass(git_repository_config_snapshot(&config, repo));
cl_git_pass(git_config_get_string_buf(&buf, config, "branch.master.remote"));
original_remote = git_buf_detach(&buf);
cl_git_pass(git_config_get_string_buf(&buf, config, "branch.master.merge"));
original_merge = git_buf_detach(&buf);
git_config_free(config);
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
cl_assert_equal_i(GIT_EEXISTS,
git_branch_move(&new_ref, original_ref, "master", 0));
cl_assert(git_error_last()->message != NULL);
cl_git_pass(git_repository_config_snapshot(&config, repo));
cl_git_pass(git_config_get_string(&str, config, "branch.master.remote"));
cl_assert_equal_s(original_remote, str);
cl_git_pass(git_config_get_string(&str, config, "branch.master.merge"));
cl_assert_equal_s(original_merge, str);
git_config_free(config);
cl_assert_equal_i(GIT_EEXISTS,
git_branch_move(&new_ref, original_ref, "cannot-fetch", 0));
cl_assert(git_error_last()->message != NULL);
cl_git_pass(git_repository_config_snapshot(&config, repo));
cl_git_pass(git_config_get_string(&str, config, "branch.master.remote"));
cl_assert_equal_s(original_remote, str);
cl_git_pass(git_config_get_string(&str, config, "branch.master.merge"));
cl_assert_equal_s(original_merge, str);
git_config_free(config);
git_reference_free(original_ref);
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/track-local"));
cl_assert_equal_i(GIT_EEXISTS,
git_branch_move(&new_ref, original_ref, "master", 0));
cl_assert(git_error_last()->message != NULL);
cl_git_pass(git_repository_config_snapshot(&config, repo));
cl_git_pass(git_config_get_string(&str, config, "branch.master.remote"));
cl_assert_equal_s(original_remote, str);
cl_git_pass(git_config_get_string(&str, config, "branch.master.merge"));
cl_assert_equal_s(original_merge, str);
git__free(original_remote); git__free(original_merge);
git_reference_free(original_ref);
git_config_free(config);
}
void test_refs_branches_move__moving_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
git_reference *original_ref, *new_ref;
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
cl_assert_equal_i(GIT_EINVALIDSPEC, git_branch_move(&new_ref, original_ref, "Inv@{id", 0));
git_reference_free(original_ref);
}
void test_refs_branches_move__can_not_move_a_non_branch(void)
{
git_reference *tag, *new_ref;
cl_git_pass(git_reference_lookup(&tag, repo, "refs/tags/e90810b"));
cl_git_fail(git_branch_move(&new_ref, tag, NEW_BRANCH_NAME, 0));
git_reference_free(tag);
}
void test_refs_branches_move__can_force_move_over_an_existing_branch(void)
{
git_reference *original_ref, *new_ref;
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
cl_git_pass(git_branch_move(&new_ref, original_ref, "master", 1));
git_reference_free(original_ref);
git_reference_free(new_ref);
}
void test_refs_branches_move__moving_a_branch_moves_related_configuration_data(void)
{
git_reference *branch;
git_reference *new_branch;
cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL));
assert_config_entry_existence(repo, "branch.track-local.remote", true);
assert_config_entry_existence(repo, "branch.track-local.merge", true);
assert_config_entry_existence(repo, "branch.moved.remote", false);
assert_config_entry_existence(repo, "branch.moved.merge", false);
cl_git_pass(git_branch_move(&new_branch, branch, "moved", 0));
git_reference_free(branch);
assert_config_entry_existence(repo, "branch.track-local.remote", false);
assert_config_entry_existence(repo, "branch.track-local.merge", false);
assert_config_entry_existence(repo, "branch.moved.remote", true);
assert_config_entry_existence(repo, "branch.moved.merge", true);
git_reference_free(new_branch);
}
void test_refs_branches_move__moving_the_branch_pointed_at_by_HEAD_updates_HEAD(void)
{
git_reference *branch;
git_reference *new_branch;
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
cl_git_pass(git_branch_move(&new_branch, branch, "master2", 0));
git_reference_free(branch);
git_reference_free(new_branch);
cl_git_pass(git_repository_head(&branch, repo));
cl_assert_equal_s("refs/heads/master2", git_reference_name(branch));
git_reference_free(branch);
}
void test_refs_branches_move__can_move_with_unicode(void)
{
git_reference *original_ref, *new_ref;
const char *new_branch_name = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D";
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
cl_git_pass(git_branch_move(&new_ref, original_ref, new_branch_name, 0));
if (cl_repo_get_bool(repo, "core.precomposeunicode"))
cl_assert_equal_s(GIT_REFS_HEADS_DIR "\xC3\x85\x73\x74\x72\xC3\xB6\x6D", git_reference_name(new_ref));
else
cl_assert_equal_s(GIT_REFS_HEADS_DIR "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D", git_reference_name(new_ref));
git_reference_free(original_ref);
git_reference_free(new_ref);
}
+45
View File
@@ -0,0 +1,45 @@
#include "clar_libgit2.h"
#include "branch.h"
static git_repository *repo;
static git_reference *ref;
void test_refs_branches_name__initialize(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
}
void test_refs_branches_name__cleanup(void)
{
git_reference_free(ref);
ref = NULL;
git_repository_free(repo);
repo = NULL;
}
void test_refs_branches_name__can_get_local_branch_name(void)
{
const char *name;
cl_git_pass(git_branch_lookup(&ref,repo,"master",GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_name(&name,ref));
cl_assert_equal_s("master",name);
}
void test_refs_branches_name__can_get_remote_branch_name(void)
{
const char *name;
cl_git_pass(git_branch_lookup(&ref,repo,"test/master",GIT_BRANCH_REMOTE));
cl_git_pass(git_branch_name(&name,ref));
cl_assert_equal_s("test/master",name);
}
void test_refs_branches_name__error_when_ref_is_no_branch(void)
{
const char *name;
cl_git_pass(git_reference_lookup(&ref,repo,"refs/notes/fanout"));
cl_git_fail(git_branch_name(&name,ref));
}
+68
View File
@@ -0,0 +1,68 @@
#include "clar_libgit2.h"
#include "branch.h"
#include "remote.h"
static git_repository *g_repo;
static const char *remote_tracking_branch_name = "refs/remotes/test/master";
static const char *expected_remote_name = "test";
static int expected_remote_name_length;
void test_refs_branches_remote__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
expected_remote_name_length = (int)strlen(expected_remote_name) + 1;
}
void test_refs_branches_remote__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_branches_remote__can_get_remote_for_branch(void)
{
git_buf remotename = {0};
cl_git_pass(git_branch_remote_name(&remotename, g_repo, remote_tracking_branch_name));
cl_assert_equal_s("test", remotename.ptr);
git_buf_dispose(&remotename);
}
void test_refs_branches_remote__no_matching_remote_returns_error(void)
{
const char *unknown = "refs/remotes/nonexistent/master";
git_buf buf;
git_error_clear();
memset(&buf, 0, sizeof(git_buf));
cl_git_fail_with(git_branch_remote_name(&buf, g_repo, unknown), GIT_ENOTFOUND);
cl_assert(git_error_last() != NULL);
}
void test_refs_branches_remote__local_remote_returns_error(void)
{
const char *local = "refs/heads/master";
git_buf buf;
git_error_clear();
memset(&buf, 0, sizeof(git_buf));
cl_git_fail_with(git_branch_remote_name(&buf, g_repo, local), GIT_ERROR);
cl_assert(git_error_last() != NULL);
}
void test_refs_branches_remote__ambiguous_remote_returns_error(void)
{
git_remote *remote;
git_buf buf;
/* Create the remote */
cl_git_pass(git_remote_create_with_fetchspec(&remote, g_repo, "addtest", "http://github.com/libgit2/libgit2", "refs/heads/*:refs/remotes/test/*"));
git_remote_free(remote);
git_error_clear();
memset(&buf, 0, sizeof(git_buf));
cl_git_fail_with(git_branch_remote_name(&buf, g_repo, remote_tracking_branch_name), GIT_EAMBIGUOUS);
cl_assert(git_error_last() != NULL);
}
+193
View File
@@ -0,0 +1,193 @@
#include "clar_libgit2.h"
#include "config/config_helpers.h"
#include "refs.h"
static git_repository *repo;
static git_reference *branch, *upstream;
void test_refs_branches_upstream__initialize(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
branch = NULL;
upstream = NULL;
}
void test_refs_branches_upstream__cleanup(void)
{
git_reference_free(upstream);
git_reference_free(branch);
branch = NULL;
git_repository_free(repo);
repo = NULL;
}
void test_refs_branches_upstream__can_retrieve_the_remote_tracking_reference_of_a_local_branch(void)
{
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
cl_git_pass(git_branch_upstream(&upstream, branch));
cl_assert_equal_s("refs/remotes/test/master", git_reference_name(upstream));
}
void test_refs_branches_upstream__can_retrieve_the_local_upstream_reference_of_a_local_branch(void)
{
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/track-local"));
cl_git_pass(git_branch_upstream(&upstream, branch));
cl_assert_equal_s("refs/heads/master", git_reference_name(upstream));
}
void test_refs_branches_upstream__cannot_retrieve_a_remote_upstream_reference_from_a_non_branch(void)
{
cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b"));
cl_git_fail(git_branch_upstream(&upstream, branch));
}
void test_refs_branches_upstream__trying_to_retrieve_a_remote_tracking_reference_from_a_plain_local_branch_returns_GIT_ENOTFOUND(void)
{
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/subtrees"));
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch));
}
void test_refs_branches_upstream__trying_to_retrieve_a_remote_tracking_reference_from_a_branch_with_no_fetchspec_returns_GIT_ENOTFOUND(void)
{
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/cannot-fetch"));
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch));
}
void test_refs_branches_upstream__upstream_remote(void)
{
git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_branch_upstream_remote(&buf, repo, "refs/heads/master"));
cl_assert_equal_s("test", buf.ptr);
git_buf_dispose(&buf);
}
void test_refs_branches_upstream__upstream_remote_empty_value(void)
{
git_repository *repository;
git_config *cfg;
git_buf buf = GIT_BUF_INIT;
repository = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_repository_config(&cfg, repository));
cl_git_pass(git_config_set_string(cfg, "branch.master.remote", ""));
cl_git_fail_with(GIT_ENOTFOUND, git_branch_upstream_remote(&buf, repository, "refs/heads/master"));
cl_git_pass(git_config_delete_entry(cfg, "branch.master.remote"));
cl_git_fail_with(GIT_ENOTFOUND, git_branch_upstream_remote(&buf, repository, "refs/heads/master"));
cl_git_sandbox_cleanup();
}
static void assert_merge_and_or_remote_key_missing(git_repository *repository, const git_commit *target, const char *entry_name)
{
git_reference *branch;
cl_assert_equal_i(GIT_OBJECT_COMMIT, git_object_type((git_object*)target));
cl_git_pass(git_branch_create(&branch, repository, entry_name, (git_commit*)target, 0));
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch));
git_reference_free(branch);
}
void test_refs_branches_upstream__retrieve_a_remote_tracking_reference_from_a_branch_with_no_remote_returns_GIT_ENOTFOUND(void)
{
git_reference *head;
git_repository *repository;
git_commit *target;
repository = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_repository_head(&head, repository));
cl_git_pass(git_reference_peel(((git_object **)&target), head, GIT_OBJECT_COMMIT));
git_reference_free(head);
assert_merge_and_or_remote_key_missing(repository, target, "remoteless");
assert_merge_and_or_remote_key_missing(repository, target, "mergeless");
assert_merge_and_or_remote_key_missing(repository, target, "mergeandremoteless");
git_commit_free(target);
cl_git_sandbox_cleanup();
}
void test_refs_branches_upstream__set_unset_upstream(void)
{
git_reference *branch;
git_repository *repository;
repository = cl_git_sandbox_init("testrepo.git");
/* remote */
cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/test"));
cl_git_pass(git_branch_set_upstream(branch, "test/master"));
assert_config_entry_value(repository, "branch.test.remote", "test");
assert_config_entry_value(repository, "branch.test.merge", "refs/heads/master");
git_reference_free(branch);
/* local */
cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/test"));
cl_git_pass(git_branch_set_upstream(branch, "master"));
assert_config_entry_value(repository, "branch.test.remote", ".");
assert_config_entry_value(repository, "branch.test.merge", "refs/heads/master");
/* unset */
cl_git_pass(git_branch_set_upstream(branch, NULL));
assert_config_entry_existence(repository, "branch.test.remote", false);
assert_config_entry_existence(repository, "branch.test.merge", false);
git_reference_free(branch);
cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/master"));
cl_git_pass(git_branch_set_upstream(branch, NULL));
assert_config_entry_existence(repository, "branch.test.remote", false);
assert_config_entry_existence(repository, "branch.test.merge", false);
git_reference_free(branch);
cl_git_sandbox_cleanup();
}
void test_refs_branches_upstream__no_fetch_refspec(void)
{
git_reference *ref, *branch;
git_repository *repo;
git_remote *remote;
git_config *cfg;
repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_remote_create_with_fetchspec(&remote, repo, "matching", ".", NULL));
cl_git_pass(git_remote_add_push(repo, "matching", ":"));
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/test"));
cl_git_pass(git_reference_create(&ref, repo, "refs/remotes/matching/master", git_reference_target(branch), 1, "fetch"));
cl_git_fail(git_branch_set_upstream(branch, "matching/master"));
cl_assert_equal_s("could not determine remote for 'refs/remotes/matching/master'",
git_error_last()->message);
/* we can't set it automatically, so let's test the user setting it by hand */
cl_git_pass(git_repository_config(&cfg, repo));
cl_git_pass(git_config_set_string(cfg, "branch.test.remote", "matching"));
cl_git_pass(git_config_set_string(cfg, "branch.test.merge", "refs/heads/master"));
/* we still can't find it because there is no rule for that reference */
cl_git_fail_with(GIT_ENOTFOUND, git_branch_upstream(&ref, branch));
git_reference_free(ref);
git_reference_free(branch);
git_remote_free(remote);
cl_git_sandbox_cleanup();
}
+36
View File
@@ -0,0 +1,36 @@
#include "clar_libgit2.h"
#include "branch.h"
static git_repository *repo;
static git_buf upstream_name;
void test_refs_branches_upstreamname__initialize(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
git_buf_init(&upstream_name, 0);
}
void test_refs_branches_upstreamname__cleanup(void)
{
git_buf_dispose(&upstream_name);
git_repository_free(repo);
repo = NULL;
}
void test_refs_branches_upstreamname__can_retrieve_the_remote_tracking_reference_name_of_a_local_branch(void)
{
cl_git_pass(git_branch_upstream_name(
&upstream_name, repo, "refs/heads/master"));
cl_assert_equal_s("refs/remotes/test/master", git_buf_cstr(&upstream_name));
}
void test_refs_branches_upstreamname__can_retrieve_the_local_upstream_reference_name_of_a_local_branch(void)
{
cl_git_pass(git_branch_upstream_name(
&upstream_name, repo, "refs/heads/track-local"));
cl_assert_equal_s("refs/heads/master", git_buf_cstr(&upstream_name));
}
+20
View File
@@ -0,0 +1,20 @@
#include "clar_libgit2.h"
void test_refs_crashes__double_free(void)
{
git_repository *repo;
git_reference *ref, *ref2;
const char *REFNAME = "refs/heads/xxx";
repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_reference_symbolic_create(&ref, repo, REFNAME, "refs/heads/master", 0, NULL));
cl_git_pass(git_reference_lookup(&ref2, repo, REFNAME));
cl_git_pass(git_reference_delete(ref));
git_reference_free(ref);
git_reference_free(ref2);
/* reference is gone from disk, so reloading it will fail */
cl_git_fail(git_reference_lookup(&ref2, repo, REFNAME));
cl_git_sandbox_cleanup();
}
+367
View File
@@ -0,0 +1,367 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "git2/reflog.h"
#include "reflog.h"
#include "ref_helpers.h"
static const char *current_master_tip = "099fabac3a9ea935598528c27f866e34089c2eff";
static const char *current_head_target = "refs/heads/master";
static git_repository *g_repo;
void test_refs_create__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
p_fsync__cnt = 0;
}
void test_refs_create__cleanup(void)
{
cl_git_sandbox_cleanup();
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1));
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 1));
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0));
}
void test_refs_create__symbolic(void)
{
/* create a new symbolic reference */
git_reference *new_reference, *looked_up_ref, *resolved_ref;
git_repository *repo2;
git_oid id;
const char *new_head_tracker = "ANOTHER_HEAD_TRACKER";
git_oid_fromstr(&id, current_master_tip);
/* Create and write the new symbolic reference */
cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0, NULL));
/* Ensure the reference can be looked-up... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker));
cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_SYMBOLIC);
cl_assert(reference_is_packed(looked_up_ref) == 0);
cl_assert_equal_s(looked_up_ref->name, new_head_tracker);
/* ...peeled.. */
cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
cl_assert(git_reference_type(resolved_ref) == GIT_REFERENCE_DIRECT);
/* ...and that it points to the current master tip */
cl_assert_equal_oid(&id, git_reference_target(resolved_ref));
git_reference_free(looked_up_ref);
git_reference_free(resolved_ref);
/* Similar test with a fresh new repository */
cl_git_pass(git_repository_open(&repo2, "testrepo"));
cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker));
cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
cl_assert_equal_oid(&id, git_reference_target(resolved_ref));
git_repository_free(repo2);
git_reference_free(new_reference);
git_reference_free(looked_up_ref);
git_reference_free(resolved_ref);
}
void test_refs_create__symbolic_with_arbitrary_content(void)
{
git_reference *new_reference, *looked_up_ref;
git_repository *repo2;
git_oid id;
const char *new_head_tracker = "ANOTHER_HEAD_TRACKER";
const char *arbitrary_target = "ARBITRARY DATA";
git_oid_fromstr(&id, current_master_tip);
/* Attempt to create symbolic ref with arbitrary data in target
* fails by default
*/
cl_git_fail(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL));
git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 0);
/* With strict target validation disabled, ref creation succeeds */
cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL));
/* Ensure the reference can be looked-up... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker));
cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_SYMBOLIC);
cl_assert(reference_is_packed(looked_up_ref) == 0);
cl_assert_equal_s(looked_up_ref->name, new_head_tracker);
git_reference_free(looked_up_ref);
/* Ensure the target is what we expect it to be */
cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target);
/* Similar test with a fresh new repository object */
cl_git_pass(git_repository_open(&repo2, "testrepo"));
/* Ensure the reference can be looked-up... */
cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker));
cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_SYMBOLIC);
cl_assert(reference_is_packed(looked_up_ref) == 0);
cl_assert_equal_s(looked_up_ref->name, new_head_tracker);
/* Ensure the target is what we expect it to be */
cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target);
git_repository_free(repo2);
git_reference_free(new_reference);
git_reference_free(looked_up_ref);
}
void test_refs_create__deep_symbolic(void)
{
/* create a deep symbolic reference */
git_reference *new_reference, *looked_up_ref, *resolved_ref;
git_oid id;
const char *new_head_tracker = "deep/rooted/tracker";
git_oid_fromstr(&id, current_master_tip);
cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0, NULL));
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker));
cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
cl_assert_equal_oid(&id, git_reference_target(resolved_ref));
git_reference_free(new_reference);
git_reference_free(looked_up_ref);
git_reference_free(resolved_ref);
}
void test_refs_create__oid(void)
{
/* create a new OID reference */
git_reference *new_reference, *looked_up_ref;
git_repository *repo2;
git_oid id;
const char *new_head = "refs/heads/new-head";
git_oid_fromstr(&id, current_master_tip);
/* Create and write the new object id reference */
cl_git_pass(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL));
/* Ensure the reference can be looked-up... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head));
cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_DIRECT);
cl_assert(reference_is_packed(looked_up_ref) == 0);
cl_assert_equal_s(looked_up_ref->name, new_head);
/* ...and that it points to the current master tip */
cl_assert_equal_oid(&id, git_reference_target(looked_up_ref));
git_reference_free(looked_up_ref);
/* Similar test with a fresh new repository */
cl_git_pass(git_repository_open(&repo2, "testrepo"));
cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head));
cl_assert_equal_oid(&id, git_reference_target(looked_up_ref));
git_repository_free(repo2);
git_reference_free(new_reference);
git_reference_free(looked_up_ref);
}
/* Can by default create a reference that targets at an unknown id */
void test_refs_create__oid_unknown_succeeds_without_strict(void)
{
git_reference *new_reference, *looked_up_ref;
git_oid id;
const char *new_head = "refs/heads/new-head";
git_oid_fromstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644");
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0));
/* Create and write the new object id reference */
cl_git_pass(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL));
git_reference_free(new_reference);
/* Ensure the reference can't be looked-up... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head));
git_reference_free(looked_up_ref);
}
/* Strict object enforcement enforces valid object id */
void test_refs_create__oid_unknown_fails_by_default(void)
{
git_reference *new_reference, *looked_up_ref;
git_oid id;
const char *new_head = "refs/heads/new-head";
git_oid_fromstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644");
/* Create and write the new object id reference */
cl_git_fail(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL));
/* Ensure the reference can't be looked-up... */
cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, new_head));
}
void test_refs_create__propagate_eexists(void)
{
int error;
git_oid oid;
git_reference *ref;
/* Make sure it works for oid and for symbolic both */
git_oid_fromstr(&oid, current_master_tip);
error = git_reference_create(&ref, g_repo, current_head_target, &oid, false, NULL);
cl_assert(error == GIT_EEXISTS);
error = git_reference_symbolic_create(&ref, g_repo, "HEAD", current_head_target, false, NULL);
cl_assert(error == GIT_EEXISTS);
}
void test_refs_create__existing_dir_propagates_edirectory(void)
{
git_reference *new_reference, *fail_reference;
git_oid id;
const char *dir_head = "refs/heads/new-dir/new-head",
*fail_head = "refs/heads/new-dir";
git_oid_fromstr(&id, current_master_tip);
/* Create and write the new object id reference */
cl_git_pass(git_reference_create(&new_reference, g_repo, dir_head, &id, 1, NULL));
cl_git_fail_with(GIT_EDIRECTORY,
git_reference_create(&fail_reference, g_repo, fail_head, &id, false, NULL));
git_reference_free(new_reference);
}
static void test_invalid_name(const char *name)
{
git_reference *new_reference;
git_oid id;
git_oid_fromstr(&id, current_master_tip);
cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_create(
&new_reference, g_repo, name, &id, 0, NULL));
cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_create(
&new_reference, g_repo, name, current_head_target, 0, NULL));
}
void test_refs_create__creating_a_reference_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
test_invalid_name("refs/heads/inv@{id");
test_invalid_name("refs/heads/back\\slash");
test_invalid_name("refs/heads/foo ");
test_invalid_name("refs/heads/foo /bar");
test_invalid_name("refs/heads/com1:bar/foo");
test_invalid_name("refs/heads/e:");
test_invalid_name("refs/heads/c:/foo");
test_invalid_name("refs/heads/foo.");
}
static void test_win32_name(const char *name)
{
git_reference *new_reference = NULL;
git_oid id;
int ret;
git_oid_fromstr(&id, current_master_tip);
ret = git_reference_create(&new_reference, g_repo, name, &id, 0, NULL);
#ifdef GIT_WIN32
cl_assert_equal_i(GIT_EINVALIDSPEC, ret);
#else
cl_git_pass(ret);
#endif
git_reference_free(new_reference);
}
void test_refs_create__creating_a_loose_ref_with_invalid_windows_name(void)
{
test_win32_name("refs/heads/foo./bar");
test_win32_name("refs/heads/aux");
test_win32_name("refs/heads/aux.foo/bar");
test_win32_name("refs/heads/com1");
}
/* Creating a loose ref involves fsync'ing the reference, the
* reflog and (on non-Windows) the containing directories.
* Creating a packed ref involves fsync'ing the packed ref file
* and (on non-Windows) the containing directory.
*/
#ifdef GIT_WIN32
static int expected_fsyncs_create = 2, expected_fsyncs_compress = 1;
#else
static int expected_fsyncs_create = 4, expected_fsyncs_compress = 2;
#endif
static void count_fsyncs(size_t *create_count, size_t *compress_count)
{
git_reference *ref = NULL;
git_refdb *refdb;
git_oid id;
p_fsync__cnt = 0;
git_oid_fromstr(&id, current_master_tip);
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/fsync_test", &id, 0, "log message"));
git_reference_free(ref);
*create_count = p_fsync__cnt;
p_fsync__cnt = 0;
cl_git_pass(git_repository_refdb(&refdb, g_repo));
cl_git_pass(git_refdb_compress(refdb));
git_refdb_free(refdb);
*compress_count = p_fsync__cnt;
p_fsync__cnt = 0;
}
void test_refs_create__does_not_fsync_by_default(void)
{
size_t create_count, compress_count;
count_fsyncs(&create_count, &compress_count);
cl_assert_equal_i(0, create_count);
cl_assert_equal_i(0, compress_count);
}
void test_refs_create__fsyncs_when_global_opt_set(void)
{
size_t create_count, compress_count;
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1));
count_fsyncs(&create_count, &compress_count);
cl_assert_equal_i(expected_fsyncs_create, create_count);
cl_assert_equal_i(expected_fsyncs_compress, compress_count);
}
void test_refs_create__fsyncs_when_repo_config_set(void)
{
size_t create_count, compress_count;
cl_repo_set_bool(g_repo, "core.fsyncObjectFiles", true);
count_fsyncs(&create_count, &compress_count);
cl_assert_equal_i(expected_fsyncs_create, create_count);
cl_assert_equal_i(expected_fsyncs_compress, compress_count);
}
+107
View File
@@ -0,0 +1,107 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "git2/reflog.h"
#include "git2/refdb.h"
#include "reflog.h"
#include "ref_helpers.h"
static const char *packed_test_head_name = "refs/heads/packed-test";
static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750";
static git_repository *g_repo;
void test_refs_delete__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_refs_delete__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_delete__packed_loose(void)
{
/* deleting a ref which is both packed and loose should remove both tracks in the filesystem */
git_reference *looked_up_ref, *another_looked_up_ref;
git_buf temp_path = GIT_BUF_INIT;
/* Ensure the loose reference exists on the file system */
cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), packed_test_head_name));
cl_assert(git_path_exists(temp_path.ptr));
/* Lookup the reference */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name));
/* Ensure it's the loose version that has been found */
cl_assert(reference_is_packed(looked_up_ref) == 0);
/* Now that the reference is deleted... */
cl_git_pass(git_reference_delete(looked_up_ref));
git_reference_free(looked_up_ref);
/* Looking up the reference once again should not retrieve it */
cl_git_fail(git_reference_lookup(&another_looked_up_ref, g_repo, packed_test_head_name));
/* Ensure the loose reference doesn't exist any longer on the file system */
cl_assert(!git_path_exists(temp_path.ptr));
git_reference_free(another_looked_up_ref);
git_buf_dispose(&temp_path);
}
void test_refs_delete__packed_only(void)
{
/* can delete a just packed reference */
git_reference *ref;
git_refdb *refdb;
git_oid id;
const char *new_ref = "refs/heads/new_ref";
git_oid_fromstr(&id, current_master_tip);
/* Create and write the new object id reference */
cl_git_pass(git_reference_create(&ref, g_repo, new_ref, &id, 0, NULL));
git_reference_free(ref);
/* Lookup the reference */
cl_git_pass(git_reference_lookup(&ref, g_repo, new_ref));
/* Ensure it's a loose reference */
cl_assert(reference_is_packed(ref) == 0);
/* Pack all existing references */
cl_git_pass(git_repository_refdb(&refdb, g_repo));
cl_git_pass(git_refdb_compress(refdb));
/* Reload the reference from disk */
git_reference_free(ref);
cl_git_pass(git_reference_lookup(&ref, g_repo, new_ref));
/* Ensure it's a packed reference */
cl_assert(reference_is_packed(ref) == 1);
/* This should pass */
cl_git_pass(git_reference_delete(ref));
git_reference_free(ref);
git_refdb_free(refdb);
}
void test_refs_delete__remove(void)
{
git_reference *ref;
/* Check that passing no old values lets us delete */
cl_git_pass(git_reference_lookup(&ref, g_repo, packed_test_head_name));
git_reference_free(ref);
cl_git_pass(git_reference_remove(g_repo, packed_test_head_name));
cl_git_fail(git_reference_lookup(&ref, g_repo, packed_test_head_name));
}
+42
View File
@@ -0,0 +1,42 @@
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *g_repo;
void test_refs_dup__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
}
void test_refs_dup__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_dup__direct(void)
{
git_reference *a, *b;
cl_git_pass(git_reference_lookup(&a, g_repo, "refs/heads/master"));
cl_git_pass(git_reference_dup(&b, a));
cl_assert(git_reference_cmp(a, b) == 0);
cl_assert(git_reference_owner(b) == g_repo);
git_reference_free(b);
git_reference_free(a);
}
void test_refs_dup__symbolic(void)
{
git_reference *a, *b;
cl_git_pass(git_reference_lookup(&a, g_repo, "HEAD"));
cl_git_pass(git_reference_dup(&b, a));
cl_assert(git_reference_cmp(a, b) == 0);
cl_assert(git_reference_owner(b) == g_repo);
git_reference_free(b);
git_reference_free(a);
}
+100
View File
@@ -0,0 +1,100 @@
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *repo;
static git_reference *fake_remote;
void test_refs_foreachglob__initialize(void)
{
git_oid id;
cl_fixture_sandbox("testrepo.git");
cl_git_pass(git_repository_open(&repo, "testrepo.git"));
cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0, NULL));
}
void test_refs_foreachglob__cleanup(void)
{
git_reference_free(fake_remote);
fake_remote = NULL;
git_repository_free(repo);
repo = NULL;
cl_fixture_cleanup("testrepo.git");
}
static int count_cb(const char *reference_name, void *payload)
{
int *count = (int *)payload;
GIT_UNUSED(reference_name);
(*count)++;
return 0;
}
static void assert_retrieval(const char *glob, int expected_count)
{
int count = 0;
cl_git_pass(git_reference_foreach_glob(repo, glob, count_cb, &count));
cl_assert_equal_i(expected_count, count);
}
void test_refs_foreachglob__retrieve_all_refs(void)
{
/* 12 heads (including one packed head) + 1 note + 2 remotes + 7 tags + 1 blob */
assert_retrieval("*", 23);
}
void test_refs_foreachglob__retrieve_remote_branches(void)
{
assert_retrieval("refs/remotes/*", 2);
}
void test_refs_foreachglob__retrieve_local_branches(void)
{
assert_retrieval("refs/heads/*", 12);
}
void test_refs_foreachglob__retrieve_nonexistant(void)
{
assert_retrieval("refs/nonexistent/*", 0);
}
void test_refs_foreachglob__retrieve_partially_named_references(void)
{
/*
* refs/heads/packed-test, refs/heads/test
* refs/remotes/test/master, refs/tags/test
*/
assert_retrieval("*test*", 4);
}
static int interrupt_cb(const char *reference_name, void *payload)
{
int *count = (int *)payload;
GIT_UNUSED(reference_name);
(*count)++;
return (*count == 11) ? -1000 : 0;
}
void test_refs_foreachglob__can_cancel(void)
{
int count = 0;
cl_assert_equal_i(-1000, git_reference_foreach_glob(
repo, "*", interrupt_cb, &count) );
cl_assert_equal_i(11, count);
}
+31
View File
@@ -0,0 +1,31 @@
#include "clar_libgit2.h"
void test_refs_isvalidname__can_detect_invalid_formats(void)
{
cl_assert_equal_i(false, git_reference_is_valid_name("refs/tags/0.17.0^{}"));
cl_assert_equal_i(false, git_reference_is_valid_name("TWO/LEVELS"));
cl_assert_equal_i(false, git_reference_is_valid_name("ONE.LEVEL"));
cl_assert_equal_i(false, git_reference_is_valid_name("HEAD/"));
cl_assert_equal_i(false, git_reference_is_valid_name("NO_TRAILING_UNDERSCORE_"));
cl_assert_equal_i(false, git_reference_is_valid_name("_NO_LEADING_UNDERSCORE"));
cl_assert_equal_i(false, git_reference_is_valid_name("HEAD/aa"));
cl_assert_equal_i(false, git_reference_is_valid_name("lower_case"));
cl_assert_equal_i(false, git_reference_is_valid_name("/stupid/name/master"));
cl_assert_equal_i(false, git_reference_is_valid_name("/"));
cl_assert_equal_i(false, git_reference_is_valid_name("//"));
cl_assert_equal_i(false, git_reference_is_valid_name(""));
cl_assert_equal_i(false, git_reference_is_valid_name("refs/heads/sub.lock/webmatrix"));
}
void test_refs_isvalidname__wont_hopefully_choke_on_valid_formats(void)
{
cl_assert_equal_i(true, git_reference_is_valid_name("refs/tags/0.17.0"));
cl_assert_equal_i(true, git_reference_is_valid_name("refs/LEVELS"));
cl_assert_equal_i(true, git_reference_is_valid_name("HEAD"));
cl_assert_equal_i(true, git_reference_is_valid_name("ONE_LEVEL"));
cl_assert_equal_i(true, git_reference_is_valid_name("refs/stash"));
cl_assert_equal_i(true, git_reference_is_valid_name("refs/remotes/origin/bim_with_3d@11296"));
cl_assert_equal_i(true, git_reference_is_valid_name("refs/master{yesterday"));
cl_assert_equal_i(true, git_reference_is_valid_name("refs/master}yesterday"));
cl_assert_equal_i(true, git_reference_is_valid_name("refs/master{yesterday}"));
}
+272
View File
@@ -0,0 +1,272 @@
#include "clar_libgit2.h"
#include "refs.h"
#include "vector.h"
static git_repository *repo;
void test_refs_iterator__initialize(void)
{
repo = cl_git_sandbox_init("testrepo.git");
}
void test_refs_iterator__cleanup(void)
{
cl_git_sandbox_cleanup();
}
static const char *refnames[] = {
"refs/blobs/annotated_tag_to_blob",
"refs/heads/br2",
"refs/heads/cannot-fetch",
"refs/heads/chomped",
"refs/heads/haacked",
"refs/heads/master",
"refs/heads/not-good",
"refs/heads/packed",
"refs/heads/packed-test",
"refs/heads/subtrees",
"refs/heads/test",
"refs/heads/track-local",
"refs/heads/trailing",
"refs/notes/fanout",
"refs/remotes/test/master",
"refs/tags/annotated_tag_to_blob",
"refs/tags/e90810b",
"refs/tags/hard_tag",
"refs/tags/point_to_blob",
"refs/tags/taggerless",
"refs/tags/test",
"refs/tags/wrapped_tag",
NULL
};
static const char *refnames_with_symlink[] = {
"refs/blobs/annotated_tag_to_blob",
"refs/heads/br2",
"refs/heads/cannot-fetch",
"refs/heads/chomped",
"refs/heads/haacked",
"refs/heads/link/a",
"refs/heads/link/b",
"refs/heads/link/c",
"refs/heads/link/d",
"refs/heads/master",
"refs/heads/not-good",
"refs/heads/packed",
"refs/heads/packed-test",
"refs/heads/subtrees",
"refs/heads/test",
"refs/heads/track-local",
"refs/heads/trailing",
"refs/notes/fanout",
"refs/remotes/test/master",
"refs/tags/annotated_tag_to_blob",
"refs/tags/e90810b",
"refs/tags/hard_tag",
"refs/tags/point_to_blob",
"refs/tags/taggerless",
"refs/tags/test",
"refs/tags/wrapped_tag",
NULL
};
static int refcmp_cb(const void *a, const void *b)
{
const git_reference *refa = (const git_reference *)a;
const git_reference *refb = (const git_reference *)b;
return strcmp(refa->name, refb->name);
}
static void assert_all_refnames_match(const char **expected, git_vector *names)
{
size_t i;
git_reference *ref;
git_vector_sort(names);
git_vector_foreach(names, i, ref) {
cl_assert(expected[i] != NULL);
cl_assert_equal_s(expected[i], ref->name);
git_reference_free(ref);
}
cl_assert(expected[i] == NULL);
git_vector_free(names);
}
void test_refs_iterator__list(void)
{
git_reference_iterator *iter;
git_vector output;
git_reference *ref;
cl_git_pass(git_vector_init(&output, 33, &refcmp_cb));
cl_git_pass(git_reference_iterator_new(&iter, repo));
while (1) {
int error = git_reference_next(&ref, iter);
if (error == GIT_ITEROVER)
break;
cl_git_pass(error);
cl_git_pass(git_vector_insert(&output, ref));
}
git_reference_iterator_free(iter);
assert_all_refnames_match(refnames, &output);
}
void test_refs_iterator__empty(void)
{
git_reference_iterator *iter;
git_odb *odb;
git_reference *ref;
git_repository *empty;
cl_git_pass(git_odb_new(&odb));
cl_git_pass(git_repository_wrap_odb(&empty, odb));
cl_git_pass(git_reference_iterator_new(&iter, empty));
cl_assert_equal_i(GIT_ITEROVER, git_reference_next(&ref, iter));
git_reference_iterator_free(iter);
git_odb_free(odb);
git_repository_free(empty);
}
static int refs_foreach_cb(git_reference *reference, void *payload)
{
git_vector *output = payload;
cl_git_pass(git_vector_insert(output, reference));
return 0;
}
void test_refs_iterator__foreach(void)
{
git_vector output;
cl_git_pass(git_vector_init(&output, 33, &refcmp_cb));
cl_git_pass(git_reference_foreach(repo, refs_foreach_cb, &output));
assert_all_refnames_match(refnames, &output);
}
void test_refs_iterator__foreach_through_symlink(void)
{
git_vector output;
#ifdef GIT_WIN32
cl_skip();
#endif
cl_git_pass(git_vector_init(&output, 32, &refcmp_cb));
cl_git_pass(p_mkdir("refs", 0777));
cl_git_mkfile("refs/a", "1234567890123456789012345678901234567890");
cl_git_mkfile("refs/b", "1234567890123456789012345678901234567890");
cl_git_mkfile("refs/c", "1234567890123456789012345678901234567890");
cl_git_mkfile("refs/d", "1234567890123456789012345678901234567890");
cl_git_pass(p_symlink("../../../refs", "testrepo.git/refs/heads/link"));
cl_git_pass(git_reference_foreach(repo, refs_foreach_cb, &output));
assert_all_refnames_match(refnames_with_symlink, &output);
}
static int refs_foreach_cancel_cb(git_reference *reference, void *payload)
{
int *cancel_after = payload;
git_reference_free(reference);
if (!*cancel_after)
return -333;
(*cancel_after)--;
return 0;
}
void test_refs_iterator__foreach_can_cancel(void)
{
int cancel_after = 3;
cl_git_fail_with(
git_reference_foreach(repo, refs_foreach_cancel_cb, &cancel_after),
-333);
cl_assert_equal_i(0, cancel_after);
}
static int refs_foreach_name_cb(const char *name, void *payload)
{
git_vector *output = payload;
cl_git_pass(git_vector_insert(output, git__strdup(name)));
return 0;
}
void test_refs_iterator__foreach_name(void)
{
git_vector output;
size_t i;
char *name;
cl_git_pass(git_vector_init(&output, 32, &git__strcmp_cb));
cl_git_pass(
git_reference_foreach_name(repo, refs_foreach_name_cb, &output));
git_vector_sort(&output);
git_vector_foreach(&output, i, name) {
cl_assert(refnames[i] != NULL);
cl_assert_equal_s(refnames[i], name);
git__free(name);
}
git_vector_free(&output);
}
static int refs_foreach_name_cancel_cb(const char *name, void *payload)
{
int *cancel_after = payload;
if (!*cancel_after)
return -333;
GIT_UNUSED(name);
(*cancel_after)--;
return 0;
}
void test_refs_iterator__foreach_name_can_cancel(void)
{
int cancel_after = 5;
cl_git_fail_with(
git_reference_foreach_name(
repo, refs_foreach_name_cancel_cb, &cancel_after),
-333);
cl_assert_equal_i(0, cancel_after);
}
void test_refs_iterator__concurrent_delete(void)
{
git_reference_iterator *iter;
size_t full_count = 0, concurrent_count = 0;
const char *name;
int error;
cl_git_sandbox_cleanup();
repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_reference_iterator_new(&iter, repo));
while ((error = git_reference_next_name(&name, iter)) == 0) {
full_count++;
}
git_reference_iterator_free(iter);
cl_assert_equal_i(GIT_ITEROVER, error);
cl_git_pass(git_reference_iterator_new(&iter, repo));
while ((error = git_reference_next_name(&name, iter)) == 0) {
cl_git_pass(git_reference_remove(repo, name));
concurrent_count++;
}
git_reference_iterator_free(iter);
cl_assert_equal_i(GIT_ITEROVER, error);
cl_assert_equal_i(full_count, concurrent_count);
}
+57
View File
@@ -0,0 +1,57 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "git2/reflog.h"
#include "reflog.h"
static git_repository *g_repo;
void test_refs_list__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_refs_list__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_list__all(void)
{
/* try to list all the references in our test repo */
git_strarray ref_list;
cl_git_pass(git_reference_list(&ref_list, g_repo));
/*{
unsigned short i;
for (i = 0; i < ref_list.count; ++i)
printf("# %s\n", ref_list.strings[i]);
}*/
/* We have exactly 12 refs in total if we include the packed ones:
* there is a reference that exists both in the packfile and as
* loose, but we only list it once */
cl_assert_equal_i((int)ref_list.count, 18);
git_strarray_free(&ref_list);
}
void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_extension(void)
{
git_strarray ref_list;
/* Create a fake locked reference */
cl_git_mkfile(
"./testrepo/.git/refs/heads/hanwen.lock",
"144344043ba4d4a405da03de3844aa829ae8be0e\n");
cl_git_pass(git_reference_list(&ref_list, g_repo));
cl_assert_equal_i((int)ref_list.count, 18);
git_strarray_free(&ref_list);
}
+47
View File
@@ -0,0 +1,47 @@
#include "clar_libgit2.h"
#include "posix.h"
static git_repository *repo;
static git_strarray ref_list;
static void ensure_no_refname_starts_with_a_forward_slash(const char *path)
{
size_t i;
cl_git_pass(git_repository_open(&repo, path));
cl_git_pass(git_reference_list(&ref_list, repo));
cl_assert(ref_list.count > 0);
for (i = 0; i < ref_list.count; i++)
cl_assert(git__prefixcmp(ref_list.strings[i], "/") != 0);
git_strarray_free(&ref_list);
git_repository_free(repo);
}
void test_refs_listall__from_repository_opened_through_workdir_path(void)
{
cl_fixture_sandbox("status");
cl_git_pass(p_rename("status/.gitted", "status/.git"));
ensure_no_refname_starts_with_a_forward_slash("status");
cl_fixture_cleanup("status");
}
void test_refs_listall__from_repository_opened_through_gitdir_path(void)
{
ensure_no_refname_starts_with_a_forward_slash(cl_fixture("testrepo.git"));
}
void test_refs_listall__from_repository_with_no_trailing_newline(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("bad_tag.git")));
cl_git_pass(git_reference_list(&ref_list, repo));
cl_assert(ref_list.count > 0);
git_strarray_free(&ref_list);
git_repository_free(repo);
}
+68
View File
@@ -0,0 +1,68 @@
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *g_repo;
void test_refs_lookup__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
}
void test_refs_lookup__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_lookup__with_resolve(void)
{
git_reference *a, *b, *temp;
cl_git_pass(git_reference_lookup(&temp, g_repo, "HEAD"));
cl_git_pass(git_reference_resolve(&a, temp));
git_reference_free(temp);
cl_git_pass(git_reference_lookup_resolved(&b, g_repo, "HEAD", 5));
cl_assert(git_reference_cmp(a, b) == 0);
git_reference_free(b);
cl_git_pass(git_reference_lookup_resolved(&b, g_repo, "HEAD_TRACKER", 5));
cl_assert(git_reference_cmp(a, b) == 0);
git_reference_free(b);
git_reference_free(a);
}
void test_refs_lookup__invalid_name(void)
{
git_oid oid;
cl_git_fail(git_reference_name_to_id(&oid, g_repo, "/refs/tags/point_to_blob"));
}
void test_refs_lookup__oid(void)
{
git_oid tag, expected;
cl_git_pass(git_reference_name_to_id(&tag, g_repo, "refs/tags/point_to_blob"));
cl_git_pass(git_oid_fromstr(&expected, "1385f264afb75a56a5bec74243be9b367ba4ca08"));
cl_assert_equal_oid(&expected, &tag);
}
void test_refs_lookup__namespace(void)
{
int error;
git_reference *ref;
error = git_reference_lookup(&ref, g_repo, "refs/heads");
cl_assert_equal_i(error, GIT_ENOTFOUND);
error = git_reference_lookup(&ref, g_repo, "refs/heads/");
cl_assert_equal_i(error, GIT_EINVALIDSPEC);
}
void test_refs_lookup__dwim_notfound(void)
{
git_reference *ref;
cl_git_fail_with(GIT_ENOTFOUND, git_reference_dwim(&ref, g_repo, "idontexist"));
cl_assert_equal_s("no reference found for shorthand 'idontexist'", git_error_last()->message);
}
+36
View File
@@ -0,0 +1,36 @@
#include "clar_libgit2.h"
#include "repository.h"
static git_repository *g_repo;
void test_refs_namespaces__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_refs_namespaces__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_namespaces__get_and_set(void)
{
cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo));
cl_git_pass(git_repository_set_namespace(g_repo, "namespace"));
cl_assert_equal_s("namespace", git_repository_get_namespace(g_repo));
cl_git_pass(git_repository_set_namespace(g_repo, NULL));
cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo));
}
void test_refs_namespaces__namespace_doesnt_show_normal_refs(void)
{
static git_strarray ref_list;
cl_git_pass(git_repository_set_namespace(g_repo, "namespace"));
cl_git_pass(git_reference_list(&ref_list, g_repo));
cl_assert_equal_i(0, ref_list.count);
git_strarray_free(&ref_list);
}
+401
View File
@@ -0,0 +1,401 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "git2/reflog.h"
#include "reflog.h"
/* Helpers */
static void ensure_refname_normalized(
unsigned int flags,
const char *input_refname,
const char *expected_refname)
{
char buffer_out[GIT_REFNAME_MAX];
cl_git_pass(git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags));
cl_assert_equal_s(expected_refname, buffer_out);
}
static void ensure_refname_invalid(unsigned int flags, const char *input_refname)
{
char buffer_out[GIT_REFNAME_MAX];
cl_assert_equal_i(
GIT_EINVALIDSPEC,
git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags));
}
void test_refs_normalize__can_normalize_a_direct_reference_name(void)
{
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "refs/dummy/a", "refs/dummy/a");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "refs/stash", "refs/stash");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "refs/tags/a", "refs/tags/a");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/a/b", "refs/heads/a/b");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/a./b", "refs/heads/a./b");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "refs///heads///a", "refs/heads/a");
}
void test_refs_normalize__cannot_normalize_any_direct_reference_name(void)
{
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "a");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "/a");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "//a");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "/refs/heads/a/");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/a/");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/a.");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/a.lock");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/foo?bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads\foo");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "refs///heads///a", "refs/heads/a");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/.a/b");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/foo/../bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/foo..bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/./foo");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "refs/heads/v@{ation");
}
void test_refs_normalize__symbolic(void)
{
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "heads\foo");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "/");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "///");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "ALL_CAPS_AND_UNDERSCORES", "ALL_CAPS_AND_UNDERSCORES");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/MixedCasing", "refs/MixedCasing");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs///heads///a", "refs/heads/a");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "HEAD", "HEAD");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "MERGE_HEAD", "MERGE_HEAD");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "FETCH_HEAD", "FETCH_HEAD");
}
/* Ported from JGit, BSD licence.
* See https://github.com/spearce/JGit/commit/e4bf8f6957bbb29362575d641d1e77a02d906739
*
* Copyright (C) 2009, Google Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Git Development Community nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
void test_refs_normalize__jgit_suite(void)
{
/* tests borrowed from JGit */
/* EmptyString */
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "/");
/* MustHaveTwoComponents */
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_NORMAL, "master");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_NORMAL, "heads/master", "heads/master");
/* ValidHead */
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master", "refs/heads/master");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/pu", "refs/heads/pu");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/z", "refs/heads/z");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/FoO", "refs/heads/FoO");
/* ValidTag */
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/tags/v1.0", "refs/tags/v1.0");
/* NoLockSuffix */
ensure_refname_invalid(GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master.lock");
/* NoDirectorySuffix */
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master/");
/* NoSpace */
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/i haz space");
/* NoAsciiControlCharacters */
{
char c;
char buffer[GIT_REFNAME_MAX];
for (c = '\1'; c < ' '; c++) {
p_snprintf(buffer, sizeof(buffer), "refs/heads/mast%cer", c);
ensure_refname_invalid(GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, buffer);
}
}
/* NoBareDot */
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/.");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/..");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/./master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/../master");
/* NoLeadingOrTrailingDot */
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, ".");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/.bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/..bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/bar.");
/* ContainsDot */
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master..pu");
/* NoMagicRefCharacters */
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master^");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/^master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "^refs/heads/master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master~");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/~master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "~refs/heads/master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master:");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/:master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, ":refs/heads/master");
/* ShellGlob */
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master?");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/?master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "?refs/heads/master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master[");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/[master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "[refs/heads/master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master*");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/*master");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "*refs/heads/master");
/* ValidSpecialCharacters */
ensure_refname_normalized
(GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/!", "refs/heads/!");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/\"", "refs/heads/\"");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/#", "refs/heads/#");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/$", "refs/heads/$");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/%", "refs/heads/%");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/&", "refs/heads/&");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/'", "refs/heads/'");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/(", "refs/heads/(");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/)", "refs/heads/)");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/+", "refs/heads/+");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/,", "refs/heads/,");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/-", "refs/heads/-");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/;", "refs/heads/;");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/<", "refs/heads/<");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/=", "refs/heads/=");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/>", "refs/heads/>");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/@", "refs/heads/@");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/]", "refs/heads/]");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/_", "refs/heads/_");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/`", "refs/heads/`");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/{", "refs/heads/{");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/|", "refs/heads/|");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/}", "refs/heads/}");
/*
* This is valid on UNIX, but not on Windows
* hence we make in invalid due to non-portability
*/
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/\\");
/* UnicodeNames */
/*
* Currently this fails.
* ensure_refname_normalized(GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/\u00e5ngstr\u00f6m", "refs/heads/\u00e5ngstr\u00f6m");
*/
/* RefLogQueryIsValidRef */
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1}");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1.hour.ago}");
}
void test_refs_normalize__buffer_has_to_be_big_enough_to_hold_the_normalized_version(void)
{
char buffer_out[21];
cl_git_pass(git_reference_normalize_name(
buffer_out, 21, "refs//heads///long///name", GIT_REFERENCE_FORMAT_NORMAL));
cl_git_fail(git_reference_normalize_name(
buffer_out, 20, "refs//heads///long///name", GIT_REFERENCE_FORMAT_NORMAL));
}
#define ONE_LEVEL_AND_REFSPEC \
GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL \
| GIT_REFERENCE_FORMAT_REFSPEC_PATTERN
void test_refs_normalize__refspec_pattern(void)
{
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/*foo/bar", "heads/*foo/bar");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/foo*/bar", "heads/foo*/bar");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/f*o/bar", "heads/f*o/bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "foo");
ensure_refname_normalized(
ONE_LEVEL_AND_REFSPEC, "FOO", "FOO");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "foo/bar", "foo/bar");
ensure_refname_normalized(
ONE_LEVEL_AND_REFSPEC, "foo/bar", "foo/bar");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "*/foo", "*/foo");
ensure_refname_normalized(
ONE_LEVEL_AND_REFSPEC, "*/foo", "*/foo");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "foo/*/bar", "foo/*/bar");
ensure_refname_normalized(
ONE_LEVEL_AND_REFSPEC, "foo/*/bar", "foo/*/bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "*");
ensure_refname_normalized(
ONE_LEVEL_AND_REFSPEC, "*", "*");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "foo/*/*");
ensure_refname_invalid(
ONE_LEVEL_AND_REFSPEC, "foo/*/*");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "*/foo/*");
ensure_refname_invalid(
ONE_LEVEL_AND_REFSPEC, "*/foo/*");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "*/*/foo");
ensure_refname_invalid(
ONE_LEVEL_AND_REFSPEC, "*/*/foo");
}
+136
View File
@@ -0,0 +1,136 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "git2/reflog.h"
#include "reflog.h"
static const char *ref_name = "refs/heads/other";
static const char *ref_master_name = "refs/heads/master";
static const char *ref_branch_name = "refs/heads/branch";
static const char *ref_test_name = "refs/heads/test";
static git_repository *g_repo;
void test_refs_overwrite__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_refs_overwrite__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_overwrite__symbolic(void)
{
/* Overwrite an existing symbolic reference */
git_reference *ref, *branch_ref;
/* The target needds to exist and we need to check the name has changed */
cl_git_pass(git_reference_symbolic_create(&branch_ref, g_repo, ref_branch_name, ref_master_name, 0, NULL));
cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_branch_name, 0, NULL));
git_reference_free(ref);
/* Ensure it points to the right place*/
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_SYMBOLIC);
cl_assert_equal_s(git_reference_symbolic_target(ref), ref_branch_name);
git_reference_free(ref);
/* Ensure we can't create it unless we force it to */
cl_git_fail(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 0, NULL));
cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 1, NULL));
git_reference_free(ref);
/* Ensure it points to the right place */
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_SYMBOLIC);
cl_assert_equal_s(git_reference_symbolic_target(ref), ref_master_name);
git_reference_free(ref);
git_reference_free(branch_ref);
}
void test_refs_overwrite__object_id(void)
{
/* Overwrite an existing object id reference */
git_reference *ref;
git_oid id;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
git_reference_free(ref);
/* Create it */
cl_git_pass(git_reference_create(&ref, g_repo, ref_name, &id, 0, NULL));
git_reference_free(ref);
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_test_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
git_reference_free(ref);
/* Ensure we can't overwrite unless we force it */
cl_git_fail(git_reference_create(&ref, g_repo, ref_name, &id, 0, NULL));
cl_git_pass(git_reference_create(&ref, g_repo, ref_name, &id, 1, NULL));
git_reference_free(ref);
/* Ensure it has been overwritten */
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name));
cl_assert_equal_oid(&id, git_reference_target(ref));
git_reference_free(ref);
}
void test_refs_overwrite__object_id_with_symbolic(void)
{
/* Overwrite an existing object id reference with a symbolic one */
git_reference *ref;
git_oid id;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
git_reference_free(ref);
cl_git_pass(git_reference_create(&ref, g_repo, ref_name, &id, 0, NULL));
git_reference_free(ref);
cl_git_fail(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 0, NULL));
cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 1, NULL));
git_reference_free(ref);
/* Ensure it points to the right place */
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_SYMBOLIC);
cl_assert_equal_s(git_reference_symbolic_target(ref), ref_master_name);
git_reference_free(ref);
}
void test_refs_overwrite__symbolic_with_object_id(void)
{
/* Overwrite an existing symbolic reference with an object id one */
git_reference *ref;
git_oid id;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
git_reference_free(ref);
/* Create the symbolic ref */
cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 0, NULL));
git_reference_free(ref);
/* It shouldn't overwrite unless we tell it to */
cl_git_fail(git_reference_create(&ref, g_repo, ref_name, &id, 0, NULL));
cl_git_pass(git_reference_create(&ref, g_repo, ref_name, &id, 1, NULL));
git_reference_free(ref);
/* Ensure it points to the right place */
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_DIRECT);
cl_assert_equal_oid(&id, git_reference_target(ref));
git_reference_free(ref);
}
+105
View File
@@ -0,0 +1,105 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "git2/reflog.h"
#include "git2/refdb.h"
#include "reflog.h"
#include "refs.h"
#include "ref_helpers.h"
static const char *loose_tag_ref_name = "refs/tags/e90810b";
static git_repository *g_repo;
void test_refs_pack__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_refs_pack__cleanup(void)
{
cl_git_sandbox_cleanup();
}
static void packall(void)
{
git_refdb *refdb;
cl_git_pass(git_repository_refdb(&refdb, g_repo));
cl_git_pass(git_refdb_compress(refdb));
git_refdb_free(refdb);
}
void test_refs_pack__empty(void)
{
/* create a packfile for an empty folder */
git_buf temp_path = GIT_BUF_INIT;
cl_git_pass(git_buf_join_n(&temp_path, '/', 3, git_repository_path(g_repo), GIT_REFS_HEADS_DIR, "empty_dir"));
cl_git_pass(git_futils_mkdir_r(temp_path.ptr, GIT_REFS_DIR_MODE));
git_buf_dispose(&temp_path);
packall();
}
void test_refs_pack__loose(void)
{
/* create a packfile from all the loose refs in a repo */
git_reference *reference;
git_buf temp_path = GIT_BUF_INIT;
/* Ensure a known loose ref can be looked up */
cl_git_pass(git_reference_lookup(&reference, g_repo, loose_tag_ref_name));
cl_assert(reference_is_packed(reference) == 0);
cl_assert_equal_s(reference->name, loose_tag_ref_name);
git_reference_free(reference);
/*
* We are now trying to pack also a loose reference
* called `points_to_blob`, to make sure we can properly
* pack weak tags
*/
packall();
/* Ensure the packed-refs file exists */
cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), GIT_PACKEDREFS_FILE));
cl_assert(git_path_exists(temp_path.ptr));
/* Ensure the known ref can still be looked up but is now packed */
cl_git_pass(git_reference_lookup(&reference, g_repo, loose_tag_ref_name));
cl_assert(reference_is_packed(reference));
cl_assert_equal_s(reference->name, loose_tag_ref_name);
/* Ensure the known ref has been removed from the loose folder structure */
cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), loose_tag_ref_name));
cl_assert(!git_path_exists(temp_path.ptr));
git_reference_free(reference);
git_buf_dispose(&temp_path);
}
void test_refs_pack__symbolic(void)
{
/* create a packfile from loose refs skipping symbolic refs */
int i;
git_oid head;
git_reference *ref;
char name[128];
cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD"));
/* make a bunch of references */
for (i = 0; i < 100; ++i) {
p_snprintf(name, sizeof(name), "refs/heads/symbolic-%03d", i);
cl_git_pass(git_reference_symbolic_create(
&ref, g_repo, name, "refs/heads/master", 0, NULL));
git_reference_free(ref);
p_snprintf(name, sizeof(name), "refs/heads/direct-%03d", i);
cl_git_pass(git_reference_create(&ref, g_repo, name, &head, 0, NULL));
git_reference_free(ref);
}
packall();
}
+131
View File
@@ -0,0 +1,131 @@
#include "clar_libgit2.h"
static git_repository *g_repo;
static git_repository *g_peel_repo;
void test_refs_peel__initialize(void)
{
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
cl_git_pass(git_repository_open(&g_peel_repo, cl_fixture("peeled.git")));
}
void test_refs_peel__cleanup(void)
{
git_repository_free(g_repo);
g_repo = NULL;
git_repository_free(g_peel_repo);
g_peel_repo = NULL;
}
static void assert_peel_generic(
git_repository *repo,
const char *ref_name,
git_object_t requested_type,
const char* expected_sha,
git_object_t expected_type)
{
git_oid expected_oid;
git_reference *ref;
git_object *peeled;
cl_git_pass(git_reference_lookup(&ref, repo, ref_name));
cl_git_pass(git_reference_peel(&peeled, ref, requested_type));
cl_git_pass(git_oid_fromstr(&expected_oid, expected_sha));
cl_assert_equal_oid(&expected_oid, git_object_id(peeled));
cl_assert_equal_i(expected_type, git_object_type(peeled));
git_object_free(peeled);
git_reference_free(ref);
}
static void assert_peel(
const char *ref_name,
git_object_t requested_type,
const char* expected_sha,
git_object_t expected_type)
{
assert_peel_generic(g_repo, ref_name, requested_type,
expected_sha, expected_type);
}
static void assert_peel_error(int error, const char *ref_name, git_object_t requested_type)
{
git_reference *ref;
git_object *peeled;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name));
cl_assert_equal_i(error, git_reference_peel(&peeled, ref, requested_type));
git_reference_free(ref);
}
void test_refs_peel__can_peel_a_tag(void)
{
assert_peel("refs/tags/test", GIT_OBJECT_TAG,
"b25fa35b38051e4ae45d4222e795f9df2e43f1d1", GIT_OBJECT_TAG);
assert_peel("refs/tags/test", GIT_OBJECT_COMMIT,
"e90810b8df3e80c413d903f631643c716887138d", GIT_OBJECT_COMMIT);
assert_peel("refs/tags/test", GIT_OBJECT_TREE,
"53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJECT_TREE);
assert_peel("refs/tags/point_to_blob", GIT_OBJECT_BLOB,
"1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OBJECT_BLOB);
}
void test_refs_peel__can_peel_a_branch(void)
{
assert_peel("refs/heads/master", GIT_OBJECT_COMMIT,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OBJECT_COMMIT);
assert_peel("refs/heads/master", GIT_OBJECT_TREE,
"944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OBJECT_TREE);
}
void test_refs_peel__can_peel_a_symbolic_reference(void)
{
assert_peel("HEAD", GIT_OBJECT_COMMIT,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OBJECT_COMMIT);
assert_peel("HEAD", GIT_OBJECT_TREE,
"944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OBJECT_TREE);
}
void test_refs_peel__cannot_peel_into_a_non_existing_target(void)
{
assert_peel_error(GIT_EINVALIDSPEC, "refs/tags/point_to_blob", GIT_OBJECT_TAG);
}
void test_refs_peel__can_peel_into_any_non_tag_object(void)
{
assert_peel("refs/heads/master", GIT_OBJECT_ANY,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OBJECT_COMMIT);
assert_peel("refs/tags/point_to_blob", GIT_OBJECT_ANY,
"1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OBJECT_BLOB);
assert_peel("refs/tags/test", GIT_OBJECT_ANY,
"e90810b8df3e80c413d903f631643c716887138d", GIT_OBJECT_COMMIT);
}
void test_refs_peel__can_peel_fully_peeled_packed_refs(void)
{
assert_peel_generic(g_peel_repo,
"refs/tags/tag-inside-tags", GIT_OBJECT_ANY,
"0df1a5865c8abfc09f1f2182e6a31be550e99f07",
GIT_OBJECT_COMMIT);
assert_peel_generic(g_peel_repo,
"refs/foo/tag-outside-tags", GIT_OBJECT_ANY,
"0df1a5865c8abfc09f1f2182e6a31be550e99f07",
GIT_OBJECT_COMMIT);
}
void test_refs_peel__can_peel_fully_peeled_tag_to_tag(void)
{
assert_peel_generic(g_peel_repo,
"refs/tags/tag-inside-tags", GIT_OBJECT_TAG,
"c2596aa0151888587ec5c0187f261e63412d9e11",
GIT_OBJECT_TAG);
assert_peel_generic(g_peel_repo,
"refs/foo/tag-outside-tags", GIT_OBJECT_TAG,
"c2596aa0151888587ec5c0187f261e63412d9e11",
GIT_OBJECT_TAG);
}
+152
View File
@@ -0,0 +1,152 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "git2/reflog.h"
#include "reflog.h"
#include "ref_helpers.h"
static const char *commit_id = "099fabac3a9ea935598528c27f866e34089c2eff";
static const char *refname = "refs/heads/master";
static const char *other_refname = "refs/heads/foo";
static const char *other_commit_id = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750";
static git_repository *g_repo;
void test_refs_races__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_refs_races__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_races__create_matching(void)
{
git_reference *ref, *ref2, *ref3;
git_oid id, other_id;
git_oid_fromstr(&id, commit_id);
git_oid_fromstr(&other_id, other_commit_id);
cl_git_fail_with(GIT_EMODIFIED, git_reference_create_matching(&ref, g_repo, refname, &other_id, 1, &other_id, NULL));
cl_git_pass(git_reference_lookup(&ref, g_repo, refname));
cl_git_pass(git_reference_create_matching(&ref2, g_repo, refname, &other_id, 1, &id, NULL));
cl_git_fail_with(GIT_EMODIFIED, git_reference_set_target(&ref3, ref, &other_id, NULL));
git_reference_free(ref);
git_reference_free(ref2);
git_reference_free(ref3);
}
void test_refs_races__symbolic_create_matching(void)
{
git_reference *ref, *ref2, *ref3;
git_oid id, other_id;
git_oid_fromstr(&id, commit_id);
git_oid_fromstr(&other_id, other_commit_id);
cl_git_fail_with(GIT_EMODIFIED, git_reference_symbolic_create_matching(&ref, g_repo, "HEAD", other_refname, 1, other_refname, NULL));
cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
cl_git_pass(git_reference_symbolic_create_matching(&ref2, g_repo, "HEAD", other_refname, 1, NULL, refname));
cl_git_fail_with(GIT_EMODIFIED, git_reference_symbolic_set_target(&ref3, ref, other_refname, NULL));
git_reference_free(ref);
git_reference_free(ref2);
git_reference_free(ref3);
}
void test_refs_races__delete(void)
{
git_reference *ref, *ref2;
git_oid id, other_id;
git_oid_fromstr(&id, commit_id);
git_oid_fromstr(&other_id, other_commit_id);
/* We can delete a value that matches */
cl_git_pass(git_reference_lookup(&ref, g_repo, refname));
cl_git_pass(git_reference_delete(ref));
git_reference_free(ref);
/* We cannot delete a symbolic value that doesn't match */
cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
cl_git_pass(git_reference_symbolic_create_matching(&ref2, g_repo, "HEAD", other_refname, 1, NULL, refname));
cl_git_fail_with(GIT_EMODIFIED, git_reference_delete(ref));
git_reference_free(ref);
git_reference_free(ref2);
cl_git_pass(git_reference_create(&ref, g_repo, refname, &id, 1, NULL));
git_reference_free(ref);
/* We cannot delete an oid value that doesn't match */
cl_git_pass(git_reference_lookup(&ref, g_repo, refname));
cl_git_pass(git_reference_create_matching(&ref2, g_repo, refname, &other_id, 1, &id, NULL));
cl_git_fail_with(GIT_EMODIFIED, git_reference_delete(ref));
git_reference_free(ref);
git_reference_free(ref2);
}
void test_refs_races__switch_oid_to_symbolic(void)
{
git_reference *ref, *ref2, *ref3;
git_oid id, other_id;
git_oid_fromstr(&id, commit_id);
git_oid_fromstr(&other_id, other_commit_id);
/* Removing a direct ref when it's currently symbolic should fail */
cl_git_pass(git_reference_lookup(&ref, g_repo, refname));
cl_git_pass(git_reference_symbolic_create(&ref2, g_repo, refname, other_refname, 1, NULL));
cl_git_fail_with(GIT_EMODIFIED, git_reference_delete(ref));
git_reference_free(ref);
git_reference_free(ref2);
cl_git_pass(git_reference_create(&ref, g_repo, refname, &id, 1, NULL));
git_reference_free(ref);
/* Updating a direct ref when it's currently symbolic should fail */
cl_git_pass(git_reference_lookup(&ref, g_repo, refname));
cl_git_pass(git_reference_symbolic_create(&ref2, g_repo, refname, other_refname, 1, NULL));
cl_git_fail_with(GIT_EMODIFIED, git_reference_set_target(&ref3, ref, &other_id, NULL));
git_reference_free(ref);
git_reference_free(ref2);
git_reference_free(ref3);
}
void test_refs_races__switch_symbolic_to_oid(void)
{
git_reference *ref, *ref2, *ref3;
git_oid id, other_id;
git_oid_fromstr(&id, commit_id);
git_oid_fromstr(&other_id, other_commit_id);
/* Removing a symbolic ref when it's currently direct should fail */
cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
cl_git_pass(git_reference_create(&ref2, g_repo, "HEAD", &id, 1, NULL));
cl_git_fail_with(GIT_EMODIFIED, git_reference_delete(ref));
git_reference_free(ref);
git_reference_free(ref2);
cl_git_pass(git_reference_symbolic_create(&ref, g_repo, "HEAD", refname, 1, NULL));
git_reference_free(ref);
/* Updating a symbolic ref when it's currently direct should fail */
cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
cl_git_pass(git_reference_create(&ref2, g_repo, "HEAD", &id, 1, NULL));
cl_git_fail_with(GIT_EMODIFIED, git_reference_symbolic_set_target(&ref3, ref, other_refname, NULL));
git_reference_free(ref);
git_reference_free(ref2);
git_reference_free(ref3);
}
+299
View File
@@ -0,0 +1,299 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "git2/reflog.h"
#include "reflog.h"
#include "ref_helpers.h"
static const char *loose_tag_ref_name = "refs/tags/e90810b";
static const char *non_existing_tag_ref_name = "refs/tags/i-do-not-exist";
static const char *head_tracker_sym_ref_name = "HEAD_TRACKER";
static const char *current_head_target = "refs/heads/master";
static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750";
static const char *packed_head_name = "refs/heads/packed";
static const char *packed_test_head_name = "refs/heads/packed-test";
static git_repository *g_repo;
void test_refs_read__initialize(void)
{
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
}
void test_refs_read__cleanup(void)
{
git_repository_free(g_repo);
g_repo = NULL;
}
void test_refs_read__loose_tag(void)
{
/* lookup a loose tag reference */
git_reference *reference;
git_object *object;
git_buf ref_name_from_tag_name = GIT_BUF_INIT;
cl_git_pass(git_reference_lookup(&reference, g_repo, loose_tag_ref_name));
cl_assert(git_reference_type(reference) & GIT_REFERENCE_DIRECT);
cl_assert(reference_is_packed(reference) == 0);
cl_assert_equal_s(reference->name, loose_tag_ref_name);
cl_git_pass(git_object_lookup(&object, g_repo, git_reference_target(reference), GIT_OBJECT_ANY));
cl_assert(object != NULL);
cl_assert(git_object_type(object) == GIT_OBJECT_TAG);
/* Ensure the name of the tag matches the name of the reference */
cl_git_pass(git_buf_joinpath(&ref_name_from_tag_name, GIT_REFS_TAGS_DIR, git_tag_name((git_tag *)object)));
cl_assert_equal_s(ref_name_from_tag_name.ptr, loose_tag_ref_name);
git_buf_dispose(&ref_name_from_tag_name);
git_object_free(object);
git_reference_free(reference);
}
void test_refs_read__nonexisting_tag(void)
{
/* lookup a loose tag reference that doesn't exist */
git_reference *reference;
cl_git_fail(git_reference_lookup(&reference, g_repo, non_existing_tag_ref_name));
git_reference_free(reference);
}
void test_refs_read__symbolic(void)
{
/* lookup a symbolic reference */
git_reference *reference, *resolved_ref;
git_object *object;
git_oid id;
cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_FILE));
cl_assert(git_reference_type(reference) & GIT_REFERENCE_SYMBOLIC);
cl_assert(reference_is_packed(reference) == 0);
cl_assert_equal_s(reference->name, GIT_HEAD_FILE);
cl_git_pass(git_reference_resolve(&resolved_ref, reference));
cl_assert(git_reference_type(resolved_ref) == GIT_REFERENCE_DIRECT);
cl_git_pass(git_object_lookup(&object, g_repo, git_reference_target(resolved_ref), GIT_OBJECT_ANY));
cl_assert(object != NULL);
cl_assert(git_object_type(object) == GIT_OBJECT_COMMIT);
git_oid_fromstr(&id, current_master_tip);
cl_assert_equal_oid(&id, git_object_id(object));
git_object_free(object);
git_reference_free(reference);
git_reference_free(resolved_ref);
}
void test_refs_read__nested_symbolic(void)
{
/* lookup a nested symbolic reference */
git_reference *reference, *resolved_ref;
git_object *object;
git_oid id;
cl_git_pass(git_reference_lookup(&reference, g_repo, head_tracker_sym_ref_name));
cl_assert(git_reference_type(reference) & GIT_REFERENCE_SYMBOLIC);
cl_assert(reference_is_packed(reference) == 0);
cl_assert_equal_s(reference->name, head_tracker_sym_ref_name);
cl_git_pass(git_reference_resolve(&resolved_ref, reference));
cl_assert(git_reference_type(resolved_ref) == GIT_REFERENCE_DIRECT);
cl_git_pass(git_object_lookup(&object, g_repo, git_reference_target(resolved_ref), GIT_OBJECT_ANY));
cl_assert(object != NULL);
cl_assert(git_object_type(object) == GIT_OBJECT_COMMIT);
git_oid_fromstr(&id, current_master_tip);
cl_assert_equal_oid(&id, git_object_id(object));
git_object_free(object);
git_reference_free(reference);
git_reference_free(resolved_ref);
}
void test_refs_read__head_then_master(void)
{
/* lookup the HEAD and resolve the master branch */
git_reference *reference, *resolved_ref, *comp_base_ref;
cl_git_pass(git_reference_lookup(&reference, g_repo, head_tracker_sym_ref_name));
cl_git_pass(git_reference_resolve(&comp_base_ref, reference));
git_reference_free(reference);
cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_FILE));
cl_git_pass(git_reference_resolve(&resolved_ref, reference));
cl_assert_equal_oid(git_reference_target(comp_base_ref), git_reference_target(resolved_ref));
git_reference_free(reference);
git_reference_free(resolved_ref);
cl_git_pass(git_reference_lookup(&reference, g_repo, current_head_target));
cl_git_pass(git_reference_resolve(&resolved_ref, reference));
cl_assert_equal_oid(git_reference_target(comp_base_ref), git_reference_target(resolved_ref));
git_reference_free(reference);
git_reference_free(resolved_ref);
git_reference_free(comp_base_ref);
}
void test_refs_read__master_then_head(void)
{
/* lookup the master branch and then the HEAD */
git_reference *reference, *master_ref, *resolved_ref;
cl_git_pass(git_reference_lookup(&master_ref, g_repo, current_head_target));
cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_FILE));
cl_git_pass(git_reference_resolve(&resolved_ref, reference));
cl_assert_equal_oid(git_reference_target(master_ref), git_reference_target(resolved_ref));
git_reference_free(reference);
git_reference_free(resolved_ref);
git_reference_free(master_ref);
}
void test_refs_read__packed(void)
{
/* lookup a packed reference */
git_reference *reference;
git_object *object;
cl_git_pass(git_reference_lookup(&reference, g_repo, packed_head_name));
cl_assert(git_reference_type(reference) & GIT_REFERENCE_DIRECT);
cl_assert(reference_is_packed(reference));
cl_assert_equal_s(reference->name, packed_head_name);
cl_git_pass(git_object_lookup(&object, g_repo, git_reference_target(reference), GIT_OBJECT_ANY));
cl_assert(object != NULL);
cl_assert(git_object_type(object) == GIT_OBJECT_COMMIT);
git_object_free(object);
git_reference_free(reference);
}
void test_refs_read__loose_first(void)
{
/* assure that a loose reference is looked up before a packed reference */
git_reference *reference;
cl_git_pass(git_reference_lookup(&reference, g_repo, packed_head_name));
git_reference_free(reference);
cl_git_pass(git_reference_lookup(&reference, g_repo, packed_test_head_name));
cl_assert(git_reference_type(reference) & GIT_REFERENCE_DIRECT);
cl_assert(reference_is_packed(reference) == 0);
cl_assert_equal_s(reference->name, packed_test_head_name);
git_reference_free(reference);
}
void test_refs_read__chomped(void)
{
git_reference *test, *chomped;
cl_git_pass(git_reference_lookup(&test, g_repo, "refs/heads/test"));
cl_git_pass(git_reference_lookup(&chomped, g_repo, "refs/heads/chomped"));
cl_assert_equal_oid(git_reference_target(test), git_reference_target(chomped));
git_reference_free(test);
git_reference_free(chomped);
}
void test_refs_read__trailing(void)
{
git_reference *test, *trailing;
cl_git_pass(git_reference_lookup(&test, g_repo, "refs/heads/test"));
cl_git_pass(git_reference_lookup(&trailing, g_repo, "refs/heads/trailing"));
cl_assert_equal_oid(git_reference_target(test), git_reference_target(trailing));
git_reference_free(trailing);
cl_git_pass(git_reference_lookup(&trailing, g_repo, "FETCH_HEAD"));
git_reference_free(test);
git_reference_free(trailing);
}
void test_refs_read__unfound_return_ENOTFOUND(void)
{
git_reference *reference;
git_oid id;
cl_assert_equal_i(GIT_ENOTFOUND,
git_reference_lookup(&reference, g_repo, "TEST_MASTER"));
cl_assert_equal_i(GIT_ENOTFOUND,
git_reference_lookup(&reference, g_repo, "refs/test/master"));
cl_assert_equal_i(GIT_ENOTFOUND,
git_reference_lookup(&reference, g_repo, "refs/tags/test/master"));
cl_assert_equal_i(GIT_ENOTFOUND,
git_reference_lookup(&reference, g_repo, "refs/tags/test/farther/master"));
cl_assert_equal_i(GIT_ENOTFOUND,
git_reference_name_to_id(&id, g_repo, "refs/tags/test/farther/master"));
}
static void assert_is_branch(const char *name, bool expected_branchness)
{
git_reference *reference;
cl_git_pass(git_reference_lookup(&reference, g_repo, name));
cl_assert_equal_i(expected_branchness, git_reference_is_branch(reference));
git_reference_free(reference);
}
void test_refs_read__can_determine_if_a_reference_is_a_local_branch(void)
{
assert_is_branch("refs/heads/master", true);
assert_is_branch("refs/heads/packed", true);
assert_is_branch("refs/remotes/test/master", false);
assert_is_branch("refs/tags/e90810b", false);
}
static void assert_is_tag(const char *name, bool expected_tagness)
{
git_reference *reference;
cl_git_pass(git_reference_lookup(&reference, g_repo, name));
cl_assert_equal_i(expected_tagness, git_reference_is_tag(reference));
git_reference_free(reference);
}
void test_refs_read__can_determine_if_a_reference_is_a_tag(void)
{
assert_is_tag("refs/tags/e90810b", true);
assert_is_tag("refs/tags/test", true);
assert_is_tag("refs/heads/packed", false);
assert_is_tag("refs/remotes/test/master", false);
}
static void assert_is_note(const char *name, bool expected_noteness)
{
git_reference *reference;
cl_git_pass(git_reference_lookup(&reference, g_repo, name));
cl_assert_equal_i(expected_noteness, git_reference_is_note(reference));
git_reference_free(reference);
}
void test_refs_read__can_determine_if_a_reference_is_a_note(void)
{
assert_is_note("refs/notes/fanout", true);
assert_is_note("refs/heads/packed", false);
assert_is_note("refs/remotes/test/master", false);
}
void test_refs_read__invalid_name_returns_EINVALIDSPEC(void)
{
git_reference *reference;
git_oid id;
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_reference_lookup(&reference, g_repo, "refs/heads/Inv@{id"));
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_reference_name_to_id(&id, g_repo, "refs/heads/Inv@{id"));
}
+25
View File
@@ -0,0 +1,25 @@
#include "git2/repository.h"
#include "git2/refs.h"
#include "common.h"
#include "util.h"
#include "buffer.h"
#include "path.h"
int reference_is_packed(git_reference *ref)
{
git_buf ref_path = GIT_BUF_INIT;
int packed;
assert(ref);
if (git_buf_joinpath(&ref_path,
git_repository_path(git_reference_owner(ref)),
git_reference_name(ref)) < 0)
return -1;
packed = !git_path_isfile(ref_path.ptr);
git_buf_dispose(&ref_path);
return packed;
}
+1
View File
@@ -0,0 +1 @@
int reference_is_packed(git_reference *ref);
+115
View File
@@ -0,0 +1,115 @@
#include "clar_libgit2.h"
#include "reflog.h"
static git_repository *g_repo;
static git_reflog *g_reflog;
static size_t entrycount;
void test_refs_reflog_drop__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
git_reflog_read(&g_reflog, g_repo, "HEAD");
entrycount = git_reflog_entrycount(g_reflog);
}
void test_refs_reflog_drop__cleanup(void)
{
git_reflog_free(g_reflog);
g_reflog = NULL;
cl_git_sandbox_cleanup();
}
void test_refs_reflog_drop__dropping_a_non_exisiting_entry_from_the_log_returns_ENOTFOUND(void)
{
cl_assert_equal_i(GIT_ENOTFOUND, git_reflog_drop(g_reflog, entrycount, 0));
cl_assert_equal_sz(entrycount, git_reflog_entrycount(g_reflog));
}
void test_refs_reflog_drop__can_drop_an_entry(void)
{
cl_assert(entrycount > 4);
cl_git_pass(git_reflog_drop(g_reflog, 2, 0));
cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog));
}
void test_refs_reflog_drop__can_drop_an_entry_and_rewrite_the_log_history(void)
{
const git_reflog_entry *before_current;
const git_reflog_entry *after_current;
git_oid before_current_old_oid, before_current_cur_oid;
cl_assert(entrycount > 4);
before_current = git_reflog_entry_byindex(g_reflog, 1);
git_oid_cpy(&before_current_old_oid, &before_current->oid_old);
git_oid_cpy(&before_current_cur_oid, &before_current->oid_cur);
cl_git_pass(git_reflog_drop(g_reflog, 1, 1));
cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog));
after_current = git_reflog_entry_byindex(g_reflog, 0);
cl_assert_equal_i(0, git_oid_cmp(&before_current_old_oid, &after_current->oid_old));
cl_assert(0 != git_oid_cmp(&before_current_cur_oid, &after_current->oid_cur));
}
void test_refs_reflog_drop__can_drop_the_oldest_entry(void)
{
const git_reflog_entry *entry;
cl_assert(entrycount > 2);
cl_git_pass(git_reflog_drop(g_reflog, entrycount - 1, 0));
cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog));
entry = git_reflog_entry_byindex(g_reflog, entrycount - 2);
cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) != 0);
}
void test_refs_reflog_drop__can_drop_the_oldest_entry_and_rewrite_the_log_history(void)
{
const git_reflog_entry *entry;
cl_assert(entrycount > 2);
cl_git_pass(git_reflog_drop(g_reflog, entrycount - 1, 1));
cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog));
entry = git_reflog_entry_byindex(g_reflog, entrycount - 2);
cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) == 0);
}
void test_refs_reflog_drop__can_drop_all_the_entries(void)
{
cl_assert(--entrycount > 0);
do {
cl_git_pass(git_reflog_drop(g_reflog, 0, 1));
} while (--entrycount > 0);
cl_git_pass(git_reflog_drop(g_reflog, 0, 1));
cl_assert_equal_i(0, (int)git_reflog_entrycount(g_reflog));
}
void test_refs_reflog_drop__can_persist_deletion_on_disk(void)
{
cl_assert(entrycount > 2);
cl_git_pass(git_reflog_drop(g_reflog, 0, 1));
cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog));
cl_git_pass(git_reflog_write(g_reflog));
git_reflog_free(g_reflog);
git_reflog_read(&g_reflog, g_repo, "HEAD");
cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog));
}
+430
View File
@@ -0,0 +1,430 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "git2/reflog.h"
#include "reflog.h"
#include "refs.h"
#include "reflog_helpers.h"
static const char *g_email = "foo@example.com";
static git_repository *g_repo;
/* Fixture setup and teardown */
void test_refs_reflog_messages__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_repository_set_ident(g_repo, "Foo Bar", g_email));
}
void test_refs_reflog_messages__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_reflog_messages__setting_head_updates_reflog(void)
{
git_object *tag;
git_signature *sig;
git_annotated_commit *annotated;
cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked")); /* 4 */
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/unborn"));
cl_git_pass(git_revparse_single(&tag, g_repo, "tags/test"));
cl_git_pass(git_repository_set_head_detached(g_repo, git_object_id(tag))); /* 3 */
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked")); /* 2 */
cl_git_pass(git_repository_set_head(g_repo, "refs/tags/test")); /* 1 */
cl_git_pass(git_repository_set_head(g_repo, "refs/remotes/test/master")); /* 0 */
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 4,
NULL, "refs/heads/haacked",
"foo@example.com",
"checkout: moving from master to haacked");
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 3,
NULL, "tags/test^{commit}",
"foo@example.com",
"checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d");
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 2,
"tags/test^{commit}", "refs/heads/haacked",
"foo@example.com",
"checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked");
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 1,
"refs/heads/haacked", "tags/test^{commit}",
"foo@example.com",
"checkout: moving from haacked to test");
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
"tags/test^{commit}", "refs/remotes/test/master",
"foo@example.com",
"checkout: moving from e90810b8df3e80c413d903f631643c716887138d to test/master");
cl_git_pass(git_annotated_commit_from_revspec(&annotated, g_repo, "haacked~0"));
cl_git_pass(git_repository_set_head_detached_from_annotated(g_repo, annotated));
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
NULL, "refs/heads/haacked",
"foo@example.com",
"checkout: moving from be3563ae3f795b2b4353bcce3a527ad0a4f7f644 to haacked~0");
git_annotated_commit_free(annotated);
git_object_free(tag);
git_signature_free(sig);
}
void test_refs_reflog_messages__setting_head_to_same_target_ignores_reflog(void)
{
size_t nentries, nentries_after;
nentries = reflog_entrycount(g_repo, GIT_HEAD_FILE);
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked"));
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked"));
nentries_after = reflog_entrycount(g_repo, GIT_HEAD_FILE);
cl_assert_equal_i(nentries + 1, nentries_after);
}
void test_refs_reflog_messages__detaching_writes_reflog(void)
{
git_signature *sig;
git_oid id;
const char *msg;
cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
msg = "checkout: moving from master to e90810b8df3e80c413d903f631643c716887138d";
git_oid_fromstr(&id, "e90810b8df3e80c413d903f631643c716887138d");
cl_git_pass(git_repository_set_head_detached(g_repo, &id));
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"e90810b8df3e80c413d903f631643c716887138d",
NULL, msg);
msg = "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked";
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked"));
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
"e90810b8df3e80c413d903f631643c716887138d",
"258f0e2a959a364e40ed6603d5d44fbb24765b10",
NULL, msg);
git_signature_free(sig);
}
void test_refs_reflog_messages__orphan_branch_does_not_count(void)
{
git_oid id;
const char *msg;
/* Have something known */
msg = "checkout: moving from master to e90810b8df3e80c413d903f631643c716887138d";
git_oid_fromstr(&id, "e90810b8df3e80c413d903f631643c716887138d");
cl_git_pass(git_repository_set_head_detached(g_repo, &id));
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"e90810b8df3e80c413d903f631643c716887138d",
NULL, msg);
/* Switching to an orphan branch does not write to the reflog */
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/orphan"));
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"e90810b8df3e80c413d903f631643c716887138d",
NULL, msg);
/* And coming back, we set the source to zero */
msg = "checkout: moving from orphan to haacked";
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked"));
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
"0000000000000000000000000000000000000000",
"258f0e2a959a364e40ed6603d5d44fbb24765b10",
NULL, msg);
}
void test_refs_reflog_messages__branch_birth(void)
{
git_signature *sig;
git_oid id;
git_tree *tree;
git_reference *ref;
const char *msg;
size_t nentries, nentries_after;
nentries = reflog_entrycount(g_repo, GIT_HEAD_FILE);
cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
cl_git_pass(git_repository_head(&ref, g_repo));
cl_git_pass(git_reference_peel((git_object **) &tree, ref, GIT_OBJECT_TREE));
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/orphan"));
nentries_after = reflog_entrycount(g_repo, GIT_HEAD_FILE);
cl_assert_equal_i(nentries, nentries_after);
msg = "message 2";
cl_git_pass(git_commit_create(&id, g_repo, "HEAD", sig, sig, NULL, msg, tree, 0, NULL));
cl_assert_equal_i(1, reflog_entrycount(g_repo, "refs/heads/orphan"));
nentries_after = reflog_entrycount(g_repo, GIT_HEAD_FILE);
cl_assert_equal_i(nentries + 1, nentries_after);
git_signature_free(sig);
git_tree_free(tree);
git_reference_free(ref);
}
void test_refs_reflog_messages__commit_on_symbolic_ref_updates_head_reflog(void)
{
git_signature *sig;
git_oid id;
git_tree *tree;
git_reference *ref1, *ref2;
const char *msg;
size_t nentries_head, nentries_master;
nentries_head = reflog_entrycount(g_repo, GIT_HEAD_FILE);
cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
cl_git_pass(git_repository_head(&ref1, g_repo));
cl_git_pass(git_reference_peel((git_object **) &tree, ref1, GIT_OBJECT_TREE));
nentries_master = reflog_entrycount(g_repo, "refs/heads/master");
msg = "message 1";
cl_git_pass(git_reference_symbolic_create(&ref2, g_repo, "refs/heads/master", "refs/heads/foo", 1, msg));
cl_assert_equal_i(0, reflog_entrycount(g_repo, "refs/heads/foo"));
cl_assert_equal_i(nentries_head, reflog_entrycount(g_repo, GIT_HEAD_FILE));
cl_assert_equal_i(nentries_master, reflog_entrycount(g_repo, "refs/heads/master"));
msg = "message 2";
cl_git_pass(git_commit_create(&id, g_repo, "HEAD", sig, sig, NULL, msg, tree, 0, NULL));
cl_assert_equal_i(1, reflog_entrycount(g_repo, "refs/heads/foo"));
cl_assert_equal_i(nentries_head + 1, reflog_entrycount(g_repo, GIT_HEAD_FILE));
cl_assert_equal_i(nentries_master, reflog_entrycount(g_repo, "refs/heads/master"));
git_signature_free(sig);
git_reference_free(ref1);
git_reference_free(ref2);
git_tree_free(tree);
}
void test_refs_reflog_messages__show_merge_for_merge_commits(void)
{
git_oid b1_oid;
git_oid b2_oid;
git_oid merge_commit_oid;
git_commit *b1_commit;
git_commit *b2_commit;
git_signature *s;
git_commit *parent_commits[2];
git_tree *tree;
cl_git_pass(git_signature_now(&s, "alice", "alice@example.com"));
cl_git_pass(git_reference_name_to_id(&b1_oid, g_repo, "HEAD"));
cl_git_pass(git_reference_name_to_id(&b2_oid, g_repo, "refs/heads/test"));
cl_git_pass(git_commit_lookup(&b1_commit, g_repo, &b1_oid));
cl_git_pass(git_commit_lookup(&b2_commit, g_repo, &b2_oid));
parent_commits[0] = b1_commit;
parent_commits[1] = b2_commit;
cl_git_pass(git_commit_tree(&tree, b1_commit));
cl_git_pass(git_commit_create(&merge_commit_oid,
g_repo, "HEAD", s, s, NULL,
"Merge commit", tree,
2, (const struct git_commit **) parent_commits));
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
NULL,
git_oid_tostr_s(&merge_commit_oid),
NULL, "commit (merge): Merge commit");
git_tree_free(tree);
git_commit_free(b1_commit);
git_commit_free(b2_commit);
git_signature_free(s);
}
void test_refs_reflog_messages__creating_a_direct_reference(void)
{
git_reference *reference;
git_oid id;
git_reflog *reflog;
const git_reflog_entry *entry;
const char *name = "refs/heads/new-head";
const char *message = "You've been logged, mate!";
cl_git_pass(git_reference_name_to_id(&id, g_repo, "HEAD"));
cl_git_pass(git_reference_create(&reference, g_repo, name, &id, 0, message));
cl_git_pass(git_reflog_read(&reflog, g_repo, name));
cl_assert_equal_sz(1, git_reflog_entrycount(reflog));
entry = git_reflog_entry_byindex(reflog, 0);
cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) == 0);
cl_assert_equal_oid(&id, &entry->oid_cur);
cl_assert_equal_s(message, entry->msg);
git_reflog_free(reflog);
git_reference_free(reference);
}
void test_refs_reflog_messages__newline_gets_replaced(void)
{
const git_reflog_entry *entry;
git_signature *signature;
git_reflog *reflog;
git_oid oid;
cl_git_pass(git_signature_now(&signature, "me", "foo@example.com"));
cl_git_pass(git_oid_fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"));
cl_git_pass(git_reflog_read(&reflog, g_repo, "HEAD"));
cl_assert_equal_sz(7, git_reflog_entrycount(reflog));
cl_git_pass(git_reflog_append(reflog, &oid, signature, "inner\nnewline"));
cl_assert_equal_sz(8, git_reflog_entrycount(reflog));
cl_assert(entry = git_reflog_entry_byindex(reflog, 0));
cl_assert_equal_s(git_reflog_entry_message(entry), "inner newline");
git_signature_free(signature);
git_reflog_free(reflog);
}
void test_refs_reflog_messages__renaming_ref(void)
{
git_reference *ref, *new_ref;
cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master"));
cl_git_pass(git_reference_rename(&new_ref, ref, "refs/heads/renamed", false,
"message"));
cl_reflog_check_entry(g_repo, git_reference_name(new_ref), 0,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"foo@example.com", "message");
git_reference_free(ref);
git_reference_free(new_ref);
}
void test_refs_reflog_messages__updating_a_direct_reference(void)
{
git_reference *ref, *ref_out, *target_ref;
git_oid target_id;
const char *message = "You've been logged, mate!";
git_reference_name_to_id(&target_id, g_repo, "refs/heads/haacked");
cl_git_pass(git_reference_lookup(&target_ref, g_repo, "refs/heads/haacked"));
cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master"));
cl_git_pass(git_reference_set_target(&ref_out, ref, &target_id, message));
cl_reflog_check_entry(g_repo, "refs/heads/master", 0,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"258f0e2a959a364e40ed6603d5d44fbb24765b10",
NULL, message);
git_reference_free(target_ref);
git_reference_free(ref);
git_reference_free(ref_out);
}
#define NEW_BRANCH_NAME "new-branch-on-the-block"
void test_refs_reflog_messages__creating_branches_default_messages(void)
{
git_buf buf = GIT_BUF_INIT;
git_annotated_commit *annotated;
git_object *obj;
git_commit *target;
git_reference *branch1, *branch2;
cl_git_pass(git_revparse_single(&obj, g_repo, "e90810b8df3"));
cl_git_pass(git_commit_lookup(&target, g_repo, git_object_id(obj)));
git_object_free(obj);
cl_git_pass(git_branch_create(&branch1, g_repo, NEW_BRANCH_NAME, target, false));
cl_git_pass(git_buf_printf(&buf, "branch: Created from %s", git_oid_tostr_s(git_commit_id(target))));
cl_reflog_check_entry(g_repo, "refs/heads/" NEW_BRANCH_NAME, 0,
GIT_OID_HEX_ZERO,
git_oid_tostr_s(git_commit_id(target)),
g_email, git_buf_cstr(&buf));
cl_git_pass(git_reference_remove(g_repo, "refs/heads/" NEW_BRANCH_NAME));
cl_git_pass(git_annotated_commit_from_revspec(&annotated, g_repo, "e90810b8df3"));
cl_git_pass(git_branch_create_from_annotated(&branch2, g_repo, NEW_BRANCH_NAME, annotated, true));
cl_reflog_check_entry(g_repo, "refs/heads/" NEW_BRANCH_NAME, 0,
GIT_OID_HEX_ZERO,
git_oid_tostr_s(git_commit_id(target)),
g_email, "branch: Created from e90810b8df3");
git_annotated_commit_free(annotated);
git_buf_dispose(&buf);
git_commit_free(target);
git_reference_free(branch1);
git_reference_free(branch2);
}
void test_refs_reflog_messages__moving_branch_default_message(void)
{
git_reference *branch;
git_reference *new_branch;
git_oid id;
cl_git_pass(git_reference_lookup(&branch, g_repo, "refs/heads/master"));
git_oid_cpy(&id, git_reference_target(branch));
cl_git_pass(git_branch_move(&new_branch, branch, "master2", 0));
cl_reflog_check_entry(g_repo, git_reference_name(new_branch), 0,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
g_email,
"branch: renamed refs/heads/master to refs/heads/master2");
git_reference_free(branch);
git_reference_free(new_branch);
}
void test_refs_reflog_messages__detaching_head_default_message(void)
{
git_reference *ref;
cl_assert_equal_i(false, git_repository_head_detached(g_repo));
cl_git_pass(git_repository_detach_head(g_repo));
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
NULL, "checkout: moving from master to a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
cl_assert_equal_i(true, git_repository_head_detached(g_repo));
/* take the repo back to its original state */
cl_git_pass(git_reference_symbolic_create(&ref, g_repo, "HEAD", "refs/heads/master",
true, "REATTACH"));
cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0,
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
NULL, "REATTACH");
cl_assert_equal_i(false, git_repository_head_detached(g_repo));
git_reference_free(ref);
}
+469
View File
@@ -0,0 +1,469 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "git2/reflog.h"
#include "reflog.h"
static const char *new_ref = "refs/heads/test-reflog";
static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750";
#define commit_msg "commit: bla bla"
static git_repository *g_repo;
/* helpers */
static void assert_signature(const git_signature *expected, const git_signature *actual)
{
cl_assert(actual);
cl_assert_equal_s(expected->name, actual->name);
cl_assert_equal_s(expected->email, actual->email);
cl_assert(expected->when.offset == actual->when.offset);
cl_assert(expected->when.time == actual->when.time);
}
/* Fixture setup and teardown */
void test_refs_reflog_reflog__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
}
void test_refs_reflog_reflog__cleanup(void)
{
cl_git_sandbox_cleanup();
}
static void assert_appends(const git_signature *committer, const git_oid *oid)
{
git_repository *repo2;
git_reference *lookedup_ref;
git_reflog *reflog;
const git_reflog_entry *entry;
/* Reopen a new instance of the repository */
cl_git_pass(git_repository_open(&repo2, "testrepo.git"));
/* Lookup the previously created branch */
cl_git_pass(git_reference_lookup(&lookedup_ref, repo2, new_ref));
/* Read and parse the reflog for this branch */
cl_git_pass(git_reflog_read(&reflog, repo2, new_ref));
cl_assert_equal_i(3, (int)git_reflog_entrycount(reflog));
/* The first one was the creation of the branch */
entry = git_reflog_entry_byindex(reflog, 2);
cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) == 0);
entry = git_reflog_entry_byindex(reflog, 1);
assert_signature(committer, entry->committer);
cl_assert(git_oid_cmp(oid, &entry->oid_old) == 0);
cl_assert(git_oid_cmp(oid, &entry->oid_cur) == 0);
cl_assert(entry->msg == NULL);
entry = git_reflog_entry_byindex(reflog, 0);
assert_signature(committer, entry->committer);
cl_assert(git_oid_cmp(oid, &entry->oid_cur) == 0);
cl_assert_equal_s(commit_msg, entry->msg);
git_reflog_free(reflog);
git_repository_free(repo2);
git_reference_free(lookedup_ref);
}
void test_refs_reflog_reflog__append_then_read(void)
{
/* write a reflog for a given reference and ensure it can be read back */
git_reference *ref;
git_oid oid;
git_signature *committer;
git_reflog *reflog;
/* Create a new branch pointing at the HEAD */
git_oid_fromstr(&oid, current_master_tip);
cl_git_pass(git_reference_create(&ref, g_repo, new_ref, &oid, 0, NULL));
git_reference_free(ref);
cl_git_pass(git_signature_now(&committer, "foo", "foo@bar"));
cl_git_pass(git_reflog_read(&reflog, g_repo, new_ref));
cl_git_pass(git_reflog_append(reflog, &oid, committer, NULL));
cl_git_pass(git_reflog_append(reflog, &oid, committer, commit_msg "\n"));
cl_git_pass(git_reflog_write(reflog));
assert_appends(committer, &oid);
git_reflog_free(reflog);
git_signature_free(committer);
}
void test_refs_reflog_reflog__renaming_the_reference_moves_the_reflog(void)
{
git_reference *master, *new_master;
git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT;
git_buf_joinpath(&master_log_path, git_repository_path(g_repo), GIT_REFLOG_DIR);
git_buf_puts(&moved_log_path, git_buf_cstr(&master_log_path));
git_buf_joinpath(&master_log_path, git_buf_cstr(&master_log_path), "refs/heads/master");
git_buf_joinpath(&moved_log_path, git_buf_cstr(&moved_log_path), "refs/moved");
cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&master_log_path)));
cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&moved_log_path)));
cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master"));
cl_git_pass(git_reference_rename(&new_master, master, "refs/moved", 0, NULL));
git_reference_free(master);
cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&master_log_path)));
cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&moved_log_path)));
git_reference_free(new_master);
git_buf_dispose(&moved_log_path);
git_buf_dispose(&master_log_path);
}
void test_refs_reflog_reflog__deleting_the_reference_deletes_the_reflog(void)
{
git_reference *master;
git_buf master_log_path = GIT_BUF_INIT;
git_buf_joinpath(&master_log_path, git_repository_path(g_repo), GIT_REFLOG_DIR);
git_buf_joinpath(&master_log_path, git_buf_cstr(&master_log_path), "refs/heads/master");
cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&master_log_path)));
cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master"));
cl_git_pass(git_reference_delete(master));
git_reference_free(master);
cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&master_log_path)));
git_buf_dispose(&master_log_path);
}
void test_refs_reflog_reflog__removes_empty_reflog_dir(void)
{
git_reference *ref;
git_buf log_path = GIT_BUF_INIT;
git_oid id;
/* Create a new branch pointing at the HEAD */
git_oid_fromstr(&id, current_master_tip);
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir/new-head", &id, 0, NULL));
git_buf_joinpath(&log_path, git_repository_path(g_repo), GIT_REFLOG_DIR);
git_buf_joinpath(&log_path, git_buf_cstr(&log_path), "refs/heads/new-dir/new-head");
cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&log_path)));
cl_git_pass(git_reference_delete(ref));
git_reference_free(ref);
/* new ref creation should succeed since new-dir is empty */
git_oid_fromstr(&id, current_master_tip);
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir", &id, 0, NULL));
git_reference_free(ref);
git_buf_dispose(&log_path);
}
void test_refs_reflog_reflog__fails_gracefully_on_nonempty_reflog_dir(void)
{
git_reference *ref;
git_buf log_path = GIT_BUF_INIT;
git_oid id;
/* Create a new branch pointing at the HEAD */
git_oid_fromstr(&id, current_master_tip);
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir/new-head", &id, 0, NULL));
git_reference_free(ref);
git_buf_joinpath(&log_path, git_repository_path(g_repo), GIT_REFLOG_DIR);
git_buf_joinpath(&log_path, git_buf_cstr(&log_path), "refs/heads/new-dir/new-head");
cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&log_path)));
/* delete the ref manually, leave the reflog */
cl_must_pass(p_unlink("testrepo.git/refs/heads/new-dir/new-head"));
/* new ref creation should fail since new-dir contains reflogs still */
git_oid_fromstr(&id, current_master_tip);
cl_git_fail_with(GIT_EDIRECTORY, git_reference_create(&ref, g_repo, "refs/heads/new-dir", &id, 0, NULL));
git_reference_free(ref);
git_buf_dispose(&log_path);
}
static void assert_has_reflog(bool expected_result, const char *name)
{
cl_assert_equal_i(expected_result, git_reference_has_log(g_repo, name));
}
void test_refs_reflog_reflog__reference_has_reflog(void)
{
assert_has_reflog(true, "HEAD");
assert_has_reflog(true, "refs/heads/master");
assert_has_reflog(false, "refs/heads/subtrees");
}
void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_returns_an_empty_one(void)
{
git_reflog *reflog;
const char *refname = "refs/heads/subtrees";
git_buf subtrees_log_path = GIT_BUF_INIT;
git_buf_join_n(&subtrees_log_path, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname);
cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&subtrees_log_path)));
cl_git_pass(git_reflog_read(&reflog, g_repo, refname));
cl_assert_equal_i(0, (int)git_reflog_entrycount(reflog));
git_reflog_free(reflog);
git_buf_dispose(&subtrees_log_path);
}
void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_succeeds(void)
{
git_reflog *reflog;
const char *refname = "refs/heads/newline";
const char *refmessage =
"Reflog*message with a newline and enough content after it to pass the GIT_REFLOG_SIZE_MIN check inside reflog_parse.";
const git_reflog_entry *entry;
git_reference *ref;
git_oid id;
git_buf logpath = GIT_BUF_INIT, logcontents = GIT_BUF_INIT;
char *star;
/* Create a new branch. */
cl_git_pass(git_oid_fromstr(&id, current_master_tip));
cl_git_pass(git_reference_create(&ref, g_repo, refname, &id, 1, refmessage));
/*
* Corrupt the branch reflog by introducing a newline inside the reflog message.
* We do this by replacing '*' with '\n'
*/
cl_git_pass(git_buf_join_n(&logpath, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname));
cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath)));
cl_assert((star = strchr(git_buf_cstr(&logcontents), '*')) != NULL);
*star = '\n';
cl_git_rewritefile(git_buf_cstr(&logpath), git_buf_cstr(&logcontents));
/*
* Confirm that the file was rewritten successfully
* and now contains a '\n' in the expected location
*/
cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath)));
cl_assert(strstr(git_buf_cstr(&logcontents), "Reflog\nmessage") != NULL);
cl_git_pass(git_reflog_read(&reflog, g_repo, refname));
cl_assert(entry = git_reflog_entry_byindex(reflog, 0));
cl_assert_equal_s(git_reflog_entry_message(entry), "Reflog");
git_reference_free(ref);
git_reflog_free(reflog);
git_buf_dispose(&logpath);
git_buf_dispose(&logcontents);
}
void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void)
{
git_reference *master, *new_master;
git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT;
git_reflog *reflog;
cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master"));
cl_git_pass(git_reflog_read(&reflog, g_repo, "refs/heads/master"));
cl_git_pass(git_reflog_write(reflog));
cl_git_pass(git_reference_rename(&new_master, master, "refs/moved", 0, NULL));
git_reference_free(master);
cl_git_fail(git_reflog_write(reflog));
git_reflog_free(reflog);
git_reference_free(new_master);
git_buf_dispose(&moved_log_path);
git_buf_dispose(&master_log_path);
}
void test_refs_reflog_reflog__renaming_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_reflog_rename(g_repo, "refs/heads/master", "refs/heads/Inv@{id"));
}
void test_refs_reflog_reflog__write_only_std_locations(void)
{
git_reference *ref;
git_oid id;
git_oid_fromstr(&id, current_master_tip);
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/foo", &id, 1, NULL));
git_reference_free(ref);
cl_git_pass(git_reference_create(&ref, g_repo, "refs/tags/foo", &id, 1, NULL));
git_reference_free(ref);
cl_git_pass(git_reference_create(&ref, g_repo, "refs/notes/foo", &id, 1, NULL));
git_reference_free(ref);
assert_has_reflog(true, "refs/heads/foo");
assert_has_reflog(false, "refs/tags/foo");
assert_has_reflog(true, "refs/notes/foo");
}
void test_refs_reflog_reflog__write_when_explicitly_active(void)
{
git_reference *ref;
git_oid id;
git_oid_fromstr(&id, current_master_tip);
git_reference_ensure_log(g_repo, "refs/tags/foo");
cl_git_pass(git_reference_create(&ref, g_repo, "refs/tags/foo", &id, 1, NULL));
git_reference_free(ref);
assert_has_reflog(true, "refs/tags/foo");
}
void test_refs_reflog_reflog__append_to_HEAD_when_changing_current_branch(void)
{
size_t nlogs, nlogs_after;
git_reference *ref;
git_reflog *log;
git_oid id;
cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
nlogs = git_reflog_entrycount(log);
git_reflog_free(log);
/* Move it back */
git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/master", &id, 1, NULL));
git_reference_free(ref);
cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
nlogs_after = git_reflog_entrycount(log);
git_reflog_free(log);
cl_assert_equal_i(nlogs_after, nlogs + 1);
}
void test_refs_reflog_reflog__do_not_append_when_no_update(void)
{
size_t nlogs, nlogs_after;
git_reference *ref, *ref2;
git_reflog *log;
cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
nlogs = git_reflog_entrycount(log);
git_reflog_free(log);
cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master"));
cl_git_pass(git_reference_create(&ref2, g_repo, "refs/heads/master",
git_reference_target(ref), 1, NULL));
git_reference_free(ref);
git_reference_free(ref2);
cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
nlogs_after = git_reflog_entrycount(log);
git_reflog_free(log);
cl_assert_equal_i(nlogs_after, nlogs);
}
static void assert_no_reflog_update(void)
{
size_t nlogs, nlogs_after;
size_t nlogs_master, nlogs_master_after;
git_reference *ref;
git_reflog *log;
git_oid id;
cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
nlogs = git_reflog_entrycount(log);
git_reflog_free(log);
cl_git_pass(git_reflog_read(&log, g_repo, "refs/heads/master"));
nlogs_master = git_reflog_entrycount(log);
git_reflog_free(log);
/* Move it back */
git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/master", &id, 1, NULL));
git_reference_free(ref);
cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
nlogs_after = git_reflog_entrycount(log);
git_reflog_free(log);
cl_assert_equal_i(nlogs_after, nlogs);
cl_git_pass(git_reflog_read(&log, g_repo, "refs/heads/master"));
nlogs_master_after = git_reflog_entrycount(log);
git_reflog_free(log);
cl_assert_equal_i(nlogs_after, nlogs);
cl_assert_equal_i(nlogs_master_after, nlogs_master);
}
void test_refs_reflog_reflog__logallrefupdates_bare_set_false(void)
{
git_config *config;
cl_git_pass(git_repository_config(&config, g_repo));
cl_git_pass(git_config_set_bool(config, "core.logallrefupdates", false));
git_config_free(config);
assert_no_reflog_update();
}
void test_refs_reflog_reflog__logallrefupdates_bare_set_always(void)
{
git_config *config;
git_reference *ref;
git_reflog *log;
git_oid id;
cl_git_pass(git_repository_config(&config, g_repo));
cl_git_pass(git_config_set_string(config, "core.logallrefupdates", "always"));
git_config_free(config);
git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
cl_git_pass(git_reference_create(&ref, g_repo, "refs/bork", &id, 1, "message"));
cl_git_pass(git_reflog_read(&log, g_repo, "refs/bork"));
cl_assert_equal_i(1, git_reflog_entrycount(log));
cl_assert_equal_s("message", git_reflog_entry_byindex(log, 0)->msg);
git_reflog_free(log);
git_reference_free(ref);
}
void test_refs_reflog_reflog__logallrefupdates_bare_unset(void)
{
git_config *config;
cl_git_pass(git_repository_config(&config, g_repo));
cl_git_pass(git_config_delete_entry(config, "core.logallrefupdates"));
git_config_free(config);
assert_no_reflog_update();
}
void test_refs_reflog_reflog__logallrefupdates_nonbare_set_false(void)
{
git_config *config;
cl_git_sandbox_cleanup();
g_repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_repository_config(&config, g_repo));
cl_git_pass(git_config_set_bool(config, "core.logallrefupdates", false));
git_config_free(config);
assert_no_reflog_update();
}
+118
View File
@@ -0,0 +1,118 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "reflog.h"
static int reflog_entry_tostr(git_buf *out, const git_reflog_entry *entry)
{
char old_oid[GIT_OID_HEXSZ], new_oid[GIT_OID_HEXSZ];
assert(out && entry);
git_oid_tostr((char *)&old_oid, GIT_OID_HEXSZ, git_reflog_entry_id_old(entry));
git_oid_tostr((char *)&new_oid, GIT_OID_HEXSZ, git_reflog_entry_id_new(entry));
return git_buf_printf(out, "%s %s %s %s", old_oid, new_oid, "somesig", git_reflog_entry_message(entry));
}
size_t reflog_entrycount(git_repository *repo, const char *name)
{
git_reflog *log;
size_t ret;
cl_git_pass(git_reflog_read(&log, repo, name));
ret = git_reflog_entrycount(log);
git_reflog_free(log);
return ret;
}
void cl_reflog_check_entry_(git_repository *repo, const char *reflog, size_t idx,
const char *old_spec, const char *new_spec,
const char *email, const char *message, const char *file, int line)
{
git_reflog *log;
const git_reflog_entry *entry;
git_buf result = GIT_BUF_INIT;
cl_git_pass(git_reflog_read(&log, repo, reflog));
entry = git_reflog_entry_byindex(log, idx);
if (entry == NULL)
clar__fail(file, line, "Reflog has no such entry", NULL, 1);
if (old_spec) {
git_object *obj = NULL;
if (git_revparse_single(&obj, repo, old_spec) == GIT_OK) {
if (git_oid_cmp(git_object_id(obj), git_reflog_entry_id_old(entry)) != 0) {
git_oid__writebuf(&result, "\tOld OID: \"", git_object_id(obj));
git_oid__writebuf(&result, "\" != \"", git_reflog_entry_id_old(entry));
git_buf_puts(&result, "\"\n");
}
git_object_free(obj);
} else {
git_oid *oid = git__calloc(1, sizeof(*oid));
git_oid_fromstr(oid, old_spec);
if (git_oid_cmp(oid, git_reflog_entry_id_old(entry)) != 0) {
git_oid__writebuf(&result, "\tOld OID: \"", oid);
git_oid__writebuf(&result, "\" != \"", git_reflog_entry_id_old(entry));
git_buf_puts(&result, "\"\n");
}
git__free(oid);
}
}
if (new_spec) {
git_object *obj = NULL;
if (git_revparse_single(&obj, repo, new_spec) == GIT_OK) {
if (git_oid_cmp(git_object_id(obj), git_reflog_entry_id_new(entry)) != 0) {
git_oid__writebuf(&result, "\tNew OID: \"", git_object_id(obj));
git_oid__writebuf(&result, "\" != \"", git_reflog_entry_id_new(entry));
git_buf_puts(&result, "\"\n");
}
git_object_free(obj);
} else {
git_oid *oid = git__calloc(1, sizeof(*oid));
git_oid_fromstr(oid, new_spec);
if (git_oid_cmp(oid, git_reflog_entry_id_new(entry)) != 0) {
git_oid__writebuf(&result, "\tNew OID: \"", oid);
git_oid__writebuf(&result, "\" != \"", git_reflog_entry_id_new(entry));
git_buf_puts(&result, "\"\n");
}
git__free(oid);
}
}
if (email && strcmp(email, git_reflog_entry_committer(entry)->email) != 0)
git_buf_printf(&result, "\tEmail: \"%s\" != \"%s\"\n", email, git_reflog_entry_committer(entry)->email);
if (message) {
const char *entry_msg = git_reflog_entry_message(entry);
if (entry_msg == NULL) entry_msg = "";
if (entry_msg && strcmp(message, entry_msg) != 0)
git_buf_printf(&result, "\tMessage: \"%s\" != \"%s\"\n", message, entry_msg);
}
if (git_buf_len(&result) != 0)
clar__fail(file, line, "Reflog entry mismatch", git_buf_cstr(&result), 1);
git_buf_dispose(&result);
git_reflog_free(log);
}
void reflog_print(git_repository *repo, const char *reflog_name)
{
git_reflog *reflog;
size_t idx;
git_buf out = GIT_BUF_INIT;
git_reflog_read(&reflog, repo, reflog_name);
for (idx = 0; idx < git_reflog_entrycount(reflog); idx++) {
const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, idx);
reflog_entry_tostr(&out, entry);
git_buf_putc(&out, '\n');
}
fprintf(stderr, "%s", git_buf_cstr(&out));
git_buf_dispose(&out);
git_reflog_free(reflog);
}
+10
View File
@@ -0,0 +1,10 @@
size_t reflog_entrycount(git_repository *repo, const char *name);
#define cl_reflog_check_entry(repo, reflog, idx, old_spec, new_spec, email, message) \
cl_reflog_check_entry_(repo, reflog, idx, old_spec, new_spec, email, message, __FILE__, __LINE__)
void cl_reflog_check_entry_(git_repository *repo, const char *reflog, size_t idx,
const char *old_spec, const char *new_spec,
const char *email, const char *message, const char *file, int line);
void reflog_print(git_repository *repo, const char *reflog_name);
+368
View File
@@ -0,0 +1,368 @@
#include "clar_libgit2.h"
#include "futils.h"
#include "git2/reflog.h"
#include "reflog.h"
#include "refs.h"
#include "ref_helpers.h"
static const char *loose_tag_ref_name = "refs/tags/e90810b";
static const char *packed_head_name = "refs/heads/packed";
static const char *packed_test_head_name = "refs/heads/packed-test";
static const char *ref_one_name = "refs/heads/one/branch";
static const char *ref_one_name_new = "refs/heads/two/branch";
static const char *ref_two_name = "refs/heads/two";
static const char *ref_master_name = "refs/heads/master";
static const char *ref_two_name_new = "refs/heads/two/two";
static git_repository *g_repo;
void test_refs_rename__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_repository_set_ident(g_repo, "me", "foo@example.com"));
}
void test_refs_rename__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_rename__loose(void)
{
/* rename a loose reference */
git_reference *looked_up_ref, *new_ref, *another_looked_up_ref;
git_buf temp_path = GIT_BUF_INIT;
const char *new_name = "refs/tags/Nemo/knows/refs.kung-fu";
/* Ensure the ref doesn't exist on the file system */
cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), new_name));
cl_assert(!git_path_exists(temp_path.ptr));
/* Retrieval of the reference to rename */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, loose_tag_ref_name));
/* ... which is indeed loose */
cl_assert(reference_is_packed(looked_up_ref) == 0);
/* Now that the reference is renamed... */
cl_git_pass(git_reference_rename(&new_ref, looked_up_ref, new_name, 0, NULL));
cl_assert_equal_s(new_ref->name, new_name);
git_reference_free(looked_up_ref);
/* ...It can't be looked-up with the old name... */
cl_git_fail(git_reference_lookup(&another_looked_up_ref, g_repo, loose_tag_ref_name));
/* ...but the new name works ok... */
cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, new_name));
cl_assert_equal_s(new_ref->name, new_name);
/* .. the new ref is loose... */
cl_assert(reference_is_packed(another_looked_up_ref) == 0);
cl_assert(reference_is_packed(new_ref) == 0);
/* ...and the ref can be found in the file system */
cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), new_name));
cl_assert(git_path_exists(temp_path.ptr));
git_reference_free(new_ref);
git_reference_free(another_looked_up_ref);
git_buf_dispose(&temp_path);
}
void test_refs_rename__packed(void)
{
/* rename a packed reference (should make it loose) */
git_reference *looked_up_ref, *new_ref, *another_looked_up_ref;
git_buf temp_path = GIT_BUF_INIT;
const char *brand_new_name = "refs/heads/brand_new_name";
/* Ensure the ref doesn't exist on the file system */
cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), packed_head_name));
cl_assert(!git_path_exists(temp_path.ptr));
/* The reference can however be looked-up... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));
/* .. and it's packed */
cl_assert(reference_is_packed(looked_up_ref) != 0);
/* Now that the reference is renamed... */
cl_git_pass(git_reference_rename(&new_ref, looked_up_ref, brand_new_name, 0, NULL));
cl_assert_equal_s(new_ref->name, brand_new_name);
git_reference_free(looked_up_ref);
/* ...It can't be looked-up with the old name... */
cl_git_fail(git_reference_lookup(&another_looked_up_ref, g_repo, packed_head_name));
/* ...but the new name works ok... */
cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, brand_new_name));
cl_assert_equal_s(another_looked_up_ref->name, brand_new_name);
/* .. the ref is no longer packed... */
cl_assert(reference_is_packed(another_looked_up_ref) == 0);
cl_assert(reference_is_packed(new_ref) == 0);
/* ...and the ref now happily lives in the file system */
cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), brand_new_name));
cl_assert(git_path_exists(temp_path.ptr));
git_reference_free(new_ref);
git_reference_free(another_looked_up_ref);
git_buf_dispose(&temp_path);
}
void test_refs_rename__packed_doesnt_pack_others(void)
{
/* renaming a packed reference does not pack another reference which happens to be in both loose and pack state */
git_reference *looked_up_ref, *another_looked_up_ref, *renamed_ref;
git_buf temp_path = GIT_BUF_INIT;
const char *brand_new_name = "refs/heads/brand_new_name";
/* Ensure the other reference exists on the file system */
cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), packed_test_head_name));
cl_assert(git_path_exists(temp_path.ptr));
/* Lookup the other reference */
cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, packed_test_head_name));
/* Ensure it's loose */
cl_assert(reference_is_packed(another_looked_up_ref) == 0);
git_reference_free(another_looked_up_ref);
/* Lookup the reference to rename */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));
/* Ensure it's packed */
cl_assert(reference_is_packed(looked_up_ref) != 0);
/* Now that the reference is renamed... */
cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, brand_new_name, 0, NULL));
git_reference_free(looked_up_ref);
/* Lookup the other reference */
cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, packed_test_head_name));
/* Ensure it's loose */
cl_assert(reference_is_packed(another_looked_up_ref) == 0);
/* Ensure the other ref still exists on the file system */
cl_assert(git_path_exists(temp_path.ptr));
git_reference_free(renamed_ref);
git_reference_free(another_looked_up_ref);
git_buf_dispose(&temp_path);
}
void test_refs_rename__name_collision(void)
{
/* can not rename a reference with the name of an existing reference */
git_reference *looked_up_ref, *renamed_ref;
/* An existing reference... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));
/* Can not be renamed to the name of another existing reference. */
cl_git_fail(git_reference_rename(&renamed_ref, looked_up_ref, packed_test_head_name, 0, NULL));
git_reference_free(looked_up_ref);
/* Failure to rename it hasn't corrupted its state */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));
cl_assert_equal_s(looked_up_ref->name, packed_head_name);
git_reference_free(looked_up_ref);
}
void test_refs_rename__invalid_name(void)
{
/* can not rename a reference with an invalid name */
git_reference *looked_up_ref, *renamed_ref;
/* An existing oid reference... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name));
/* Can not be renamed with an invalid name. */
cl_assert_equal_i(
GIT_EINVALIDSPEC,
git_reference_rename(&renamed_ref, looked_up_ref, "Hello! I'm a very invalid name.", 0, NULL));
/* Can not be renamed outside of the refs hierarchy
* unless it's ALL_CAPS_AND_UNDERSCORES.
*/
cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_rename(&renamed_ref, looked_up_ref, "i-will-sudo-you", 0, NULL));
/* Failure to rename it hasn't corrupted its state */
git_reference_free(looked_up_ref);
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name));
cl_assert_equal_s(looked_up_ref->name, packed_test_head_name);
git_reference_free(looked_up_ref);
}
void test_refs_rename__force_loose_packed(void)
{
/* can force-rename a packed reference with the name of an existing loose and packed reference */
git_reference *looked_up_ref, *renamed_ref;
git_oid oid;
/* An existing reference... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));
git_oid_cpy(&oid, git_reference_target(looked_up_ref));
/* Can be force-renamed to the name of another existing reference. */
cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, packed_test_head_name, 1, NULL));
git_reference_free(looked_up_ref);
git_reference_free(renamed_ref);
/* Check we actually renamed it */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name));
cl_assert_equal_s(looked_up_ref->name, packed_test_head_name);
cl_assert_equal_oid(&oid, git_reference_target(looked_up_ref));
git_reference_free(looked_up_ref);
/* And that the previous one doesn't exist any longer */
cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));
}
void test_refs_rename__force_loose(void)
{
/* can force-rename a loose reference with the name of an existing loose reference */
git_reference *looked_up_ref, *renamed_ref;
git_oid oid;
/* An existing reference... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, "refs/heads/br2"));
git_oid_cpy(&oid, git_reference_target(looked_up_ref));
/* Can be force-renamed to the name of another existing reference. */
cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, "refs/heads/test", 1, NULL));
git_reference_free(looked_up_ref);
git_reference_free(renamed_ref);
/* Check we actually renamed it */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, "refs/heads/test"));
cl_assert_equal_s(looked_up_ref->name, "refs/heads/test");
cl_assert_equal_oid(&oid, git_reference_target(looked_up_ref));
git_reference_free(looked_up_ref);
/* And that the previous one doesn't exist any longer */
cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, "refs/heads/br2"));
git_reference_free(looked_up_ref);
}
void test_refs_rename__overwrite(void)
{
/* can not overwrite name of existing reference */
git_reference *ref, *ref_one, *ref_one_new, *ref_two;
git_refdb *refdb;
git_oid id;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
/* Create loose references */
cl_git_pass(git_reference_create(&ref_one, g_repo, ref_one_name, &id, 0, NULL));
cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name, &id, 0, NULL));
/* Pack everything */
cl_git_pass(git_repository_refdb(&refdb, g_repo));
cl_git_pass(git_refdb_compress(refdb));
/* Attempt to create illegal reference */
cl_git_fail(git_reference_create(&ref_one_new, g_repo, ref_one_name_new, &id, 0, NULL));
/* Illegal reference couldn't be created so this is supposed to fail */
cl_git_fail(git_reference_lookup(&ref_one_new, g_repo, ref_one_name_new));
git_reference_free(ref);
git_reference_free(ref_one);
git_reference_free(ref_one_new);
git_reference_free(ref_two);
git_refdb_free(refdb);
}
void test_refs_rename__prefix(void)
{
/* can be renamed to a new name prefixed with the old name */
git_reference *ref, *ref_two, *looked_up_ref, *renamed_ref;
git_oid id;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
/* Create loose references */
cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name, &id, 0, NULL));
/* An existing reference... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name));
/* Can be rename to a new name starting with the old name. */
cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, ref_two_name_new, 0, NULL));
git_reference_free(looked_up_ref);
git_reference_free(renamed_ref);
/* Check we actually renamed it */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new));
cl_assert_equal_s(looked_up_ref->name, ref_two_name_new);
git_reference_free(looked_up_ref);
cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name));
git_reference_free(ref);
git_reference_free(ref_two);
git_reference_free(looked_up_ref);
}
void test_refs_rename__move_up(void)
{
/* can move a reference to a upper reference hierarchy */
git_reference *ref, *ref_two, *looked_up_ref, *renamed_ref;
git_oid id;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
cl_assert(git_reference_type(ref) & GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
/* Create loose references */
cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name_new, &id, 0, NULL));
git_reference_free(ref_two);
/* An existing reference... */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new));
/* Can be renamed upward the reference tree. */
cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, ref_two_name, 0, NULL));
git_reference_free(looked_up_ref);
git_reference_free(renamed_ref);
/* Check we actually renamed it */
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name));
cl_assert_equal_s(looked_up_ref->name, ref_two_name);
git_reference_free(looked_up_ref);
cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new));
git_reference_free(ref);
git_reference_free(looked_up_ref);
}
void test_refs_rename__propagate_eexists(void)
{
git_reference *ref, *new_ref;
cl_git_pass(git_reference_lookup(&ref, g_repo, packed_head_name));
cl_assert_equal_i(GIT_EEXISTS, git_reference_rename(&new_ref, ref, packed_test_head_name, 0, NULL));
git_reference_free(ref);
}
+864
View File
@@ -0,0 +1,864 @@
#include "clar_libgit2.h"
#include "git2/revparse.h"
#include "buffer.h"
#include "refs.h"
#include "path.h"
static git_repository *g_repo;
static git_object *g_obj;
/* Helpers */
static void test_object_and_ref_inrepo(
const char *spec,
const char *expected_oid,
const char *expected_refname,
git_repository *repo,
bool assert_reference_retrieval)
{
char objstr[64] = {0};
git_object *obj = NULL;
git_reference *ref = NULL;
int error;
error = git_revparse_ext(&obj, &ref, repo, spec);
if (expected_oid != NULL) {
cl_git_pass(error);
git_oid_fmt(objstr, git_object_id(obj));
cl_assert_equal_s(objstr, expected_oid);
} else
cl_git_fail(error);
if (assert_reference_retrieval) {
if (expected_refname == NULL)
cl_assert(NULL == ref);
else
cl_assert_equal_s(expected_refname, git_reference_name(ref));
}
git_object_free(obj);
git_reference_free(ref);
}
static void test_object_inrepo(const char *spec, const char *expected_oid, git_repository *repo)
{
test_object_and_ref_inrepo(spec, expected_oid, NULL, repo, false);
}
static void test_id_inrepo(
const char *spec,
const char *expected_left,
const char *expected_right,
git_revparse_mode_t expected_flags,
git_repository *repo)
{
git_revspec revspec;
int error = git_revparse(&revspec, repo, spec);
if (expected_left) {
char str[64] = {0};
cl_assert_equal_i(0, error);
git_oid_fmt(str, git_object_id(revspec.from));
cl_assert_equal_s(str, expected_left);
git_object_free(revspec.from);
} else {
cl_assert_equal_i(GIT_ENOTFOUND, error);
}
if (expected_right) {
char str[64] = {0};
git_oid_fmt(str, git_object_id(revspec.to));
cl_assert_equal_s(str, expected_right);
git_object_free(revspec.to);
}
if (expected_flags)
cl_assert_equal_i(expected_flags, revspec.flags);
}
static void test_object(const char *spec, const char *expected_oid)
{
test_object_inrepo(spec, expected_oid, g_repo);
}
static void test_object_and_ref(const char *spec, const char *expected_oid, const char *expected_refname)
{
test_object_and_ref_inrepo(spec, expected_oid, expected_refname, g_repo, true);
}
static void test_rangelike(const char *rangelike,
const char *expected_left,
const char *expected_right,
git_revparse_mode_t expected_revparseflags)
{
char objstr[64] = {0};
git_revspec revspec;
int error;
error = git_revparse(&revspec, g_repo, rangelike);
if (expected_left != NULL) {
cl_assert_equal_i(0, error);
cl_assert_equal_i(revspec.flags, expected_revparseflags);
git_oid_fmt(objstr, git_object_id(revspec.from));
cl_assert_equal_s(objstr, expected_left);
git_oid_fmt(objstr, git_object_id(revspec.to));
cl_assert_equal_s(objstr, expected_right);
} else
cl_assert(error != 0);
git_object_free(revspec.from);
git_object_free(revspec.to);
}
static void test_id(
const char *spec,
const char *expected_left,
const char *expected_right,
git_revparse_mode_t expected_flags)
{
test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo);
}
static void test_invalid_revspec(const char* invalid_spec)
{
git_revspec revspec;
cl_assert_equal_i(
GIT_EINVALIDSPEC, git_revparse(&revspec, g_repo, invalid_spec));
}
void test_refs_revparse__initialize(void)
{
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
}
void test_refs_revparse__cleanup(void)
{
git_repository_free(g_repo);
}
void test_refs_revparse__nonexistant_object(void)
{
test_object("this-does-not-exist", NULL);
test_object("this-does-not-exist^1", NULL);
test_object("this-does-not-exist~2", NULL);
}
static void assert_invalid_single_spec(const char *invalid_spec)
{
cl_assert_equal_i(
GIT_EINVALIDSPEC, git_revparse_single(&g_obj, g_repo, invalid_spec));
}
void test_refs_revparse__invalid_reference_name(void)
{
assert_invalid_single_spec("this doesn't make sense");
assert_invalid_single_spec("Inv@{id");
assert_invalid_single_spec("");
}
void test_refs_revparse__shas(void)
{
test_object("c47800c7266a2be04c571c04d5a6614691ea99bd", "c47800c7266a2be04c571c04d5a6614691ea99bd");
test_object("c47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd");
}
void test_refs_revparse__head(void)
{
test_object("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("HEAD^0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("HEAD~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
}
void test_refs_revparse__full_refs(void)
{
test_object("refs/heads/master", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("refs/heads/test", "e90810b8df3e80c413d903f631643c716887138d");
test_object("refs/tags/test", "b25fa35b38051e4ae45d4222e795f9df2e43f1d1");
}
void test_refs_revparse__partial_refs(void)
{
test_object("point_to_blob", "1385f264afb75a56a5bec74243be9b367ba4ca08");
test_object("packed-test", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045");
test_object("br2", "a4a7dce85cf63874e984719f4fdd239f5145052f");
}
void test_refs_revparse__describe_output(void)
{
test_object("blah-7-gc47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd");
test_object("not-good", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
}
void test_refs_revparse__nth_parent(void)
{
assert_invalid_single_spec("be3563a^-1");
assert_invalid_single_spec("^");
assert_invalid_single_spec("be3563a^{tree}^");
assert_invalid_single_spec("point_to_blob^{blob}^");
assert_invalid_single_spec("this doesn't make sense^1");
test_object("be3563a^1", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("be3563a^", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("be3563a^2", "c47800c7266a2be04c571c04d5a6614691ea99bd");
test_object("be3563a^1^1", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045");
test_object("be3563a^^", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045");
test_object("be3563a^2^1", "5b5b025afb0b4c913b4c338a42934a3863bf3644");
test_object("be3563a^0", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("be3563a^{commit}^", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("be3563a^42", NULL);
}
void test_refs_revparse__not_tag(void)
{
test_object("point_to_blob^{}", "1385f264afb75a56a5bec74243be9b367ba4ca08");
test_object("wrapped_tag^{}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master^{}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master^{tree}^{}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162");
test_object("e90810b^{}", "e90810b8df3e80c413d903f631643c716887138d");
test_object("tags/e90810b^{}", "e90810b8df3e80c413d903f631643c716887138d");
test_object("e908^{}", "e90810b8df3e80c413d903f631643c716887138d");
}
void test_refs_revparse__to_type(void)
{
assert_invalid_single_spec("wrapped_tag^{trip}");
test_object("point_to_blob^{commit}", NULL);
cl_assert_equal_i(
GIT_EPEEL, git_revparse_single(&g_obj, g_repo, "wrapped_tag^{blob}"));
test_object("wrapped_tag^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("wrapped_tag^{tree}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162");
test_object("point_to_blob^{blob}", "1385f264afb75a56a5bec74243be9b367ba4ca08");
test_object("master^{commit}^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
}
void test_refs_revparse__linear_history(void)
{
assert_invalid_single_spec("~");
test_object("foo~bar", NULL);
assert_invalid_single_spec("master~bar");
assert_invalid_single_spec("master~-1");
assert_invalid_single_spec("master~0bar");
assert_invalid_single_spec("this doesn't make sense~2");
assert_invalid_single_spec("be3563a^{tree}~");
assert_invalid_single_spec("point_to_blob^{blob}~");
test_object("master~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master~1", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("master~2", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("master~1~1", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("master~~", "9fd738e8f7967c078dceed8190330fc8648ee56a");
}
void test_refs_revparse__chaining(void)
{
assert_invalid_single_spec("master@{0}@{0}");
assert_invalid_single_spec("@{u}@{-1}");
assert_invalid_single_spec("@{-1}@{-1}");
assert_invalid_single_spec("@{-3}@{0}");
test_object("master@{0}~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("@{u}@{0}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("@{-1}@{0}", "a4a7dce85cf63874e984719f4fdd239f5145052f");
test_object("@{-4}@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("master~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("master~1^2", "c47800c7266a2be04c571c04d5a6614691ea99bd");
test_object("master^1^2~1", "5b5b025afb0b4c913b4c338a42934a3863bf3644");
test_object("master^^2^", "5b5b025afb0b4c913b4c338a42934a3863bf3644");
test_object("master^1^1^1^1^1", "8496071c1b46c854b31185ea97743be6a8774479");
test_object("master^^1^2^1", NULL);
}
void test_refs_revparse__upstream(void)
{
assert_invalid_single_spec("e90810b@{u}");
assert_invalid_single_spec("refs/tags/e90810b@{u}");
test_object("refs/heads/e90810b@{u}", NULL);
test_object("master@{upstream}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("heads/master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("refs/heads/master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
}
void test_refs_revparse__ordinal(void)
{
assert_invalid_single_spec("master@{-2}");
/* TODO: make the test below actually fail
* cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{1a}"));
*/
test_object("nope@{0}", NULL);
test_object("master@{31415}", NULL);
test_object("@{1000}", NULL);
test_object("@{2}", NULL);
test_object("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("master@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("heads/master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("refs/heads/master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
}
void test_refs_revparse__previous_head(void)
{
assert_invalid_single_spec("@{-xyz}");
assert_invalid_single_spec("@{-0}");
assert_invalid_single_spec("@{-1b}");
test_object("@{-42}", NULL);
test_object("@{-2}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("@{-1}", "a4a7dce85cf63874e984719f4fdd239f5145052f");
}
static void create_fake_stash_reference_and_reflog(git_repository *repo)
{
git_reference *master, *new_master;
git_buf log_path = GIT_BUF_INIT;
git_buf_joinpath(&log_path, git_repository_path(repo), "logs/refs/fakestash");
cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&log_path)));
cl_git_pass(git_reference_lookup(&master, repo, "refs/heads/master"));
cl_git_pass(git_reference_rename(&new_master, master, "refs/fakestash", 0, NULL));
git_reference_free(master);
cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&log_path)));
git_buf_dispose(&log_path);
git_reference_free(new_master);
}
void test_refs_revparse__reflog_of_a_ref_under_refs(void)
{
git_repository *repo = cl_git_sandbox_init("testrepo.git");
test_object_inrepo("refs/fakestash", NULL, repo);
create_fake_stash_reference_and_reflog(repo);
/*
* $ git reflog -1 refs/fakestash
* a65fedf refs/fakestash@{0}: commit: checking in
*
* $ git reflog -1 refs/fakestash@{0}
* a65fedf refs/fakestash@{0}: commit: checking in
*
* $ git reflog -1 fakestash
* a65fedf fakestash@{0}: commit: checking in
*
* $ git reflog -1 fakestash@{0}
* a65fedf fakestash@{0}: commit: checking in
*/
test_object_inrepo("refs/fakestash", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo);
test_object_inrepo("refs/fakestash@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo);
test_object_inrepo("fakestash", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo);
test_object_inrepo("fakestash@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo);
cl_git_sandbox_cleanup();
}
void test_refs_revparse__revwalk(void)
{
test_object("master^{/not found in any commit}", NULL);
test_object("master^{/merge}", NULL);
assert_invalid_single_spec("master^{/((}");
test_object("master^{/anoth}", "5b5b025afb0b4c913b4c338a42934a3863bf3644");
test_object("master^{/Merge}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("br2^{/Merge}", "a4a7dce85cf63874e984719f4fdd239f5145052f");
test_object("master^{/fo.rth}", "9fd738e8f7967c078dceed8190330fc8648ee56a");
}
void test_refs_revparse__date(void)
{
/*
* $ git reflog HEAD --date=iso
* a65fedf HEAD@{2012-04-30 08:23:41 -0900}: checkout: moving from br2 to master
* a4a7dce HEAD@{2012-04-30 08:23:37 -0900}: commit: checking in
* c47800c HEAD@{2012-04-30 08:23:28 -0900}: checkout: moving from master to br2
* a65fedf HEAD@{2012-04-30 08:23:23 -0900}: commit:
* be3563a HEAD@{2012-04-30 10:22:43 -0700}: clone: from /Users/ben/src/libgit2/tes
*
* $ git reflog HEAD --date=raw
* a65fedf HEAD@{1335806621 -0900}: checkout: moving from br2 to master
* a4a7dce HEAD@{1335806617 -0900}: commit: checking in
* c47800c HEAD@{1335806608 -0900}: checkout: moving from master to br2
* a65fedf HEAD@{1335806603 -0900}: commit:
* be3563a HEAD@{1335806563 -0700}: clone: from /Users/ben/src/libgit2/tests/resour
*/
test_object("HEAD@{10 years ago}", NULL);
test_object("HEAD@{1 second}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("HEAD@{1 second ago}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("HEAD@{2 days ago}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
/*
* $ git reflog master --date=iso
* a65fedf master@{2012-04-30 09:23:23 -0800}: commit: checking in
* be3563a master@{2012-04-30 09:22:43 -0800}: clone: from /Users/ben/src...
*
* $ git reflog master --date=raw
* a65fedf master@{1335806603 -0800}: commit: checking in
* be3563a master@{1335806563 -0800}: clone: from /Users/ben/src/libgit2/tests/reso
*/
/*
* $ git reflog -1 "master@{2012-04-30 17:22:42 +0000}"
* warning: Log for 'master' only goes back to Mon, 30 Apr 2012 09:22:43 -0800.
*/
test_object("master@{2012-04-30 17:22:42 +0000}", NULL);
test_object("master@{2012-04-30 09:22:42 -0800}", NULL);
/*
* $ git reflog -1 "master@{2012-04-30 17:22:43 +0000}"
* be3563a master@{Mon Apr 30 09:22:43 2012 -0800}: clone: from /Users/ben/src/libg
*/
test_object("master@{2012-04-30 17:22:43 +0000}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("master@{2012-04-30 09:22:43 -0800}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
/*
* $ git reflog -1 "master@{2012-4-30 09:23:27 -0800}"
* a65fedf master@{Mon Apr 30 09:23:23 2012 -0800}: commit: checking in
*/
test_object("master@{2012-4-30 09:23:27 -0800}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
/*
* $ git reflog -1 master@{2012-05-03}
* a65fedf master@{Mon Apr 30 09:23:23 2012 -0800}: commit: checking in
*/
test_object("master@{2012-05-03}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
/*
* $ git reflog -1 "master@{1335806603}"
* a65fedf
*
* $ git reflog -1 "master@{1335806602}"
* be3563a
*/
test_object("master@{1335806603}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master@{1335806602}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
}
void test_refs_revparse__colon(void)
{
assert_invalid_single_spec(":/");
assert_invalid_single_spec("point_to_blob:readme.txt");
cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); /* Not implemented */
test_object(":/not found in any commit", NULL);
test_object("subtrees:ab/42.txt", NULL);
test_object("subtrees:ab/4.txt/nope", NULL);
test_object("subtrees:nope", NULL);
test_object("test/master^1:branch_file.txt", NULL);
/* From tags */
test_object("test:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf");
test_object("tags/test:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf");
test_object("e90810b:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf");
test_object("tags/e90810b:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf");
/* From commits */
test_object("a65f:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc");
/* From trees */
test_object("a65f^{tree}:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc");
test_object("944c:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc");
/* Retrieving trees */
test_object("master:", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162");
test_object("subtrees:", "ae90f12eea699729ed24555e40b9fd669da12a12");
test_object("subtrees:ab", "f1425cef211cc08caa31e7b545ffb232acb098c3");
test_object("subtrees:ab/", "f1425cef211cc08caa31e7b545ffb232acb098c3");
/* Retrieving blobs */
test_object("subtrees:ab/4.txt", "d6c93164c249c8000205dd4ec5cbca1b516d487f");
test_object("subtrees:ab/de/fgh/1.txt", "1f67fc4386b2d171e0d21be1c447e12660561f9b");
test_object("master:README", "a8233120f6ad708f843d861ce2b7228ec4e3dec6");
test_object("master:new.txt", "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd");
test_object(":/Merge", "a4a7dce85cf63874e984719f4fdd239f5145052f");
test_object(":/one", "c47800c7266a2be04c571c04d5a6614691ea99bd");
test_object(":/packed commit t", "41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9");
test_object("test/master^2:branch_file.txt", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057");
test_object("test/master@{1}:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc");
}
void test_refs_revparse__disambiguation(void)
{
/*
* $ git show e90810b
* tag e90810b
* Tagger: Vicent Marti <tanoku@gmail.com>
* Date: Thu Aug 12 03:59:17 2010 +0200
*
* This is a very simple tag.
*
* commit e90810b8df3e80c413d903f631643c716887138d
* Author: Vicent Marti <tanoku@gmail.com>
* Date: Thu Aug 5 18:42:20 2010 +0200
*
* Test commit 2
*
* diff --git a/readme.txt b/readme.txt
* index 6336846..0266163 100644
* --- a/readme.txt
* +++ b/readme.txt
* @@ -1 +1,2 @@
* Testing a readme.txt
* +Now we add a single line here
*
* $ git show-ref e90810b
* 7b4384978d2493e851f9cca7858815fac9b10980 refs/tags/e90810b
*
*/
test_object("e90810b", "7b4384978d2493e851f9cca7858815fac9b10980");
/*
* $ git show e90810
* commit e90810b8df3e80c413d903f631643c716887138d
* Author: Vicent Marti <tanoku@gmail.com>
* Date: Thu Aug 5 18:42:20 2010 +0200
*
* Test commit 2
*
* diff --git a/readme.txt b/readme.txt
* index 6336846..0266163 100644
* --- a/readme.txt
* +++ b/readme.txt
* @@ -1 +1,2 @@
* Testing a readme.txt
* +Now we add a single line here
*/
test_object("e90810", "e90810b8df3e80c413d903f631643c716887138d");
}
void test_refs_revparse__a_too_short_objectid_returns_EAMBIGUOUS(void)
{
cl_assert_equal_i(
GIT_EAMBIGUOUS, git_revparse_single(&g_obj, g_repo, "e90"));
}
/*
* $ echo "aabqhq" | git hash-object -t blob --stdin
* dea509d0b3cb8ee0650f6ca210bc83f4678851ba
*
* $ echo "aaazvc" | git hash-object -t blob --stdin
* dea509d097ce692e167dfc6a48a7a280cc5e877e
*/
void test_refs_revparse__a_not_precise_enough_objectid_returns_EAMBIGUOUS(void)
{
git_repository *repo;
git_index *index;
git_object *obj;
repo = cl_git_sandbox_init("testrepo");
cl_git_mkfile("testrepo/one.txt", "aabqhq\n");
cl_git_mkfile("testrepo/two.txt", "aaazvc\n");
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_add_bypath(index, "one.txt"));
cl_git_pass(git_index_add_bypath(index, "two.txt"));
cl_git_fail_with(git_revparse_single(&obj, repo, "dea509d0"), GIT_EAMBIGUOUS);
cl_git_pass(git_revparse_single(&obj, repo, "dea509d09"));
git_object_free(obj);
git_index_free(index);
cl_git_sandbox_cleanup();
}
void test_refs_revparse__issue_994(void)
{
git_repository *repo;
git_reference *head, *with_at;
git_object *target;
repo = cl_git_sandbox_init("testrepo.git");
cl_assert_equal_i(GIT_ENOTFOUND,
git_revparse_single(&target, repo, "origin/bim_with_3d@11296"));
cl_assert_equal_i(GIT_ENOTFOUND,
git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296"));
cl_git_pass(git_repository_head(&head, repo));
cl_git_pass(git_reference_create(
&with_at,
repo,
"refs/remotes/origin/bim_with_3d@11296",
git_reference_target(head),
0,
NULL));
cl_git_pass(git_revparse_single(&target, repo, "origin/bim_with_3d@11296"));
git_object_free(target);
cl_git_pass(git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296"));
git_object_free(target);
git_reference_free(with_at);
git_reference_free(head);
cl_git_sandbox_cleanup();
}
/**
* $ git rev-parse blah-7-gc47800c
* c47800c7266a2be04c571c04d5a6614691ea99bd
*
* $ git rev-parse HEAD~3
* 4a202b346bb0fb0db7eff3cffeb3c70babbd2045
*
* $ git branch blah-7-gc47800c HEAD~3
*
* $ git rev-parse blah-7-gc47800c
* 4a202b346bb0fb0db7eff3cffeb3c70babbd2045
*/
void test_refs_revparse__try_to_retrieve_branch_before_described_tag(void)
{
git_repository *repo;
git_reference *branch;
git_object *target;
char sha[GIT_OID_HEXSZ + 1];
repo = cl_git_sandbox_init("testrepo.git");
test_object_inrepo("blah-7-gc47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd", repo);
cl_git_pass(git_revparse_single(&target, repo, "HEAD~3"));
cl_git_pass(git_branch_create(&branch, repo, "blah-7-gc47800c", (git_commit *)target, 0));
git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target));
test_object_inrepo("blah-7-gc47800c", sha, repo);
git_reference_free(branch);
git_object_free(target);
cl_git_sandbox_cleanup();
}
/**
* $ git rev-parse a65fedf39aefe402d3bb6e24df4d4f5fe4547750
* a65fedf39aefe402d3bb6e24df4d4f5fe4547750
*
* $ git rev-parse HEAD~3
* 4a202b346bb0fb0db7eff3cffeb3c70babbd2045
*
* $ git branch a65fedf39aefe402d3bb6e24df4d4f5fe4547750 HEAD~3
*
* $ git rev-parse a65fedf39aefe402d3bb6e24df4d4f5fe4547750
* a65fedf39aefe402d3bb6e24df4d4f5fe4547750
*
* $ git rev-parse heads/a65fedf39aefe402d3bb6e24df4d4f5fe4547750
* 4a202b346bb0fb0db7eff3cffeb3c70babbd2045
*/
void test_refs_revparse__try_to_retrieve_sha_before_branch(void)
{
git_repository *repo;
git_reference *branch;
git_object *target;
char sha[GIT_OID_HEXSZ + 1];
repo = cl_git_sandbox_init("testrepo.git");
test_object_inrepo("a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo);
cl_git_pass(git_revparse_single(&target, repo, "HEAD~3"));
cl_git_pass(git_branch_create(&branch, repo, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", (git_commit *)target, 0));
git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target));
test_object_inrepo("a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo);
test_object_inrepo("heads/a65fedf39aefe402d3bb6e24df4d4f5fe4547750", sha, repo);
git_reference_free(branch);
git_object_free(target);
cl_git_sandbox_cleanup();
}
/**
* $ git rev-parse c47800
* c47800c7266a2be04c571c04d5a6614691ea99bd
*
* $ git rev-parse HEAD~3
* 4a202b346bb0fb0db7eff3cffeb3c70babbd2045
*
* $ git branch c47800 HEAD~3
*
* $ git rev-parse c47800
* 4a202b346bb0fb0db7eff3cffeb3c70babbd2045
*/
void test_refs_revparse__try_to_retrieve_branch_before_abbrev_sha(void)
{
git_repository *repo;
git_reference *branch;
git_object *target;
char sha[GIT_OID_HEXSZ + 1];
repo = cl_git_sandbox_init("testrepo.git");
test_object_inrepo("c47800", "c47800c7266a2be04c571c04d5a6614691ea99bd", repo);
cl_git_pass(git_revparse_single(&target, repo, "HEAD~3"));
cl_git_pass(git_branch_create(&branch, repo, "c47800", (git_commit *)target, 0));
git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target));
test_object_inrepo("c47800", sha, repo);
git_reference_free(branch);
git_object_free(target);
cl_git_sandbox_cleanup();
}
void test_refs_revparse__range(void)
{
assert_invalid_single_spec("be3563a^1..be3563a");
test_rangelike("be3563a^1..be3563a",
"9fd738e8f7967c078dceed8190330fc8648ee56a",
"be3563ae3f795b2b4353bcce3a527ad0a4f7f644",
GIT_REVPARSE_RANGE);
test_rangelike("be3563a^1...be3563a",
"9fd738e8f7967c078dceed8190330fc8648ee56a",
"be3563ae3f795b2b4353bcce3a527ad0a4f7f644",
GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
test_rangelike("be3563a^1.be3563a", NULL, NULL, 0);
}
void test_refs_revparse__parses_range_operator(void)
{
test_id("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVPARSE_SINGLE);
test_id("HEAD~3..HEAD",
"4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
GIT_REVPARSE_RANGE);
test_id("HEAD~3...HEAD",
"4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
test_id("HEAD~3..",
"4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
GIT_REVPARSE_RANGE);
test_id("HEAD~3...",
"4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
test_id("..HEAD~3",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
GIT_REVPARSE_RANGE);
test_id("...HEAD~3",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
test_id("...",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
test_invalid_revspec("..");
}
void test_refs_revparse__ext_retrieves_both_the_reference_and_its_target(void)
{
test_object_and_ref(
"master@{upstream}",
"be3563ae3f795b2b4353bcce3a527ad0a4f7f644",
"refs/remotes/test/master");
test_object_and_ref(
"@{-1}",
"a4a7dce85cf63874e984719f4fdd239f5145052f",
"refs/heads/br2");
}
void test_refs_revparse__ext_can_expand_short_reference_names(void)
{
test_object_and_ref(
"master",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"refs/heads/master");
test_object_and_ref(
"HEAD",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
"refs/heads/master");
test_object_and_ref(
"tags/test",
"b25fa35b38051e4ae45d4222e795f9df2e43f1d1",
"refs/tags/test");
}
void test_refs_revparse__ext_returns_NULL_reference_when_expression_points_at_a_revision(void)
{
test_object_and_ref(
"HEAD~3",
"4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
NULL);
test_object_and_ref(
"HEAD~0",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
NULL);
test_object_and_ref(
"HEAD^0",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
NULL);
test_object_and_ref(
"@{-1}@{0}",
"a4a7dce85cf63874e984719f4fdd239f5145052f",
NULL);
}
void test_refs_revparse__ext_returns_NULL_reference_when_expression_points_at_a_tree_content(void)
{
test_object_and_ref(
"tags/test:readme.txt",
"0266163a49e280c4f5ed1e08facd36a2bd716bcf",
NULL);
}
void test_refs_revparse__uneven_sizes(void)
{
test_object("a65fedf39aefe402d3bb6e24df4d4f5fe454775",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("a65fedf39aefe402d3bb6e24df4d4f5fe45477",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("a65fedf39aefe402d3bb6e24df4d4f5fe4547",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("a65fedf39aefe402d3bb6e24df4d",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
}
+99
View File
@@ -0,0 +1,99 @@
#include "clar_libgit2.h"
#include "repository.h"
#include "git2/reflog.h"
#include "reflog.h"
#include "git2/refs.h"
static const char *ref_name = "refs/heads/other";
static const char *ref_master_name = "refs/heads/master";
static const char *ref_test_name = "refs/heads/test";
static git_repository *g_repo;
void test_refs_setter__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_refs_setter__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_setter__update_direct(void)
{
git_reference *ref, *test_ref, *new_ref;
git_oid id;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
cl_assert(git_reference_type(ref) == GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
git_reference_free(ref);
cl_git_pass(git_reference_lookup(&test_ref, g_repo, ref_test_name));
cl_assert(git_reference_type(test_ref) == GIT_REFERENCE_DIRECT);
cl_git_pass(git_reference_set_target(&new_ref, test_ref, &id, NULL));
git_reference_free(test_ref);
git_reference_free(new_ref);
cl_git_pass(git_reference_lookup(&test_ref, g_repo, ref_test_name));
cl_assert(git_reference_type(test_ref) == GIT_REFERENCE_DIRECT);
cl_assert_equal_oid(&id, git_reference_target(test_ref));
git_reference_free(test_ref);
}
void test_refs_setter__update_symbolic(void)
{
git_reference *head, *new_head;
cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD"));
cl_assert(git_reference_type(head) == GIT_REFERENCE_SYMBOLIC);
cl_assert(strcmp(git_reference_symbolic_target(head), ref_master_name) == 0);
cl_git_pass(git_reference_symbolic_set_target(&new_head, head, ref_test_name, NULL));
git_reference_free(new_head);
git_reference_free(head);
cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD"));
cl_assert(git_reference_type(head) == GIT_REFERENCE_SYMBOLIC);
cl_assert(strcmp(git_reference_symbolic_target(head), ref_test_name) == 0);
git_reference_free(head);
}
void test_refs_setter__cant_update_direct_with_symbolic(void)
{
/* Overwrite an existing object id reference with a symbolic one */
git_reference *ref, *new;
git_oid id;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
cl_assert(git_reference_type(ref) == GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
cl_git_fail(git_reference_symbolic_set_target(&new, ref, ref_name, NULL));
git_reference_free(ref);
}
void test_refs_setter__cant_update_symbolic_with_direct(void)
{
/* Overwrite an existing symbolic reference with an object id one */
git_reference *ref, *new;
git_oid id;
cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
cl_assert(git_reference_type(ref) == GIT_REFERENCE_DIRECT);
git_oid_cpy(&id, git_reference_target(ref));
git_reference_free(ref);
/* Create the symbolic ref */
cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 0, NULL));
/* Can't set an OID on a direct ref */
cl_git_fail(git_reference_set_target(&new, ref, &id, NULL));
git_reference_free(ref);
}
+27
View File
@@ -0,0 +1,27 @@
#include "clar_libgit2.h"
#include "repository.h"
void assert_shorthand(git_repository *repo, const char *refname, const char *shorthand)
{
git_reference *ref;
cl_git_pass(git_reference_lookup(&ref, repo, refname));
cl_assert_equal_s(git_reference_shorthand(ref), shorthand);
git_reference_free(ref);
}
void test_refs_shorthand__0(void)
{
git_repository *repo;
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
assert_shorthand(repo, "refs/heads/master", "master");
assert_shorthand(repo, "refs/tags/test", "test");
assert_shorthand(repo, "refs/remotes/test/master", "test/master");
assert_shorthand(repo, "refs/notes/fanout", "notes/fanout");
git_repository_free(repo);
}
+157
View File
@@ -0,0 +1,157 @@
#include "clar_libgit2.h"
#include "git2/transaction.h"
static git_repository *g_repo;
static git_transaction *g_tx;
void test_refs_transactions__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_transaction_new(&g_tx, g_repo));
}
void test_refs_transactions__cleanup(void)
{
git_transaction_free(g_tx);
cl_git_sandbox_cleanup();
}
void test_refs_transactions__single_ref_oid(void)
{
git_reference *ref;
git_oid id;
git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master"));
cl_git_pass(git_transaction_set_target(g_tx, "refs/heads/master", &id, NULL, NULL));
cl_git_pass(git_transaction_commit(g_tx));
cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master"));
cl_assert(!git_oid_cmp(&id, git_reference_target(ref)));
git_reference_free(ref);
}
void test_refs_transactions__single_ref_symbolic(void)
{
git_reference *ref;
cl_git_pass(git_transaction_lock_ref(g_tx, "HEAD"));
cl_git_pass(git_transaction_set_symbolic_target(g_tx, "HEAD", "refs/heads/foo", NULL, NULL));
cl_git_pass(git_transaction_commit(g_tx));
cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
cl_assert_equal_s("refs/heads/foo", git_reference_symbolic_target(ref));
git_reference_free(ref);
}
void test_refs_transactions__single_ref_mix_types(void)
{
git_reference *ref;
git_oid id;
git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master"));
cl_git_pass(git_transaction_lock_ref(g_tx, "HEAD"));
cl_git_pass(git_transaction_set_symbolic_target(g_tx, "refs/heads/master", "refs/heads/foo", NULL, NULL));
cl_git_pass(git_transaction_set_target(g_tx, "HEAD", &id, NULL, NULL));
cl_git_pass(git_transaction_commit(g_tx));
cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master"));
cl_assert_equal_s("refs/heads/foo", git_reference_symbolic_target(ref));
git_reference_free(ref);
cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
cl_assert(!git_oid_cmp(&id, git_reference_target(ref)));
git_reference_free(ref);
}
void test_refs_transactions__single_ref_delete(void)
{
git_reference *ref;
cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master"));
cl_git_pass(git_transaction_remove(g_tx, "refs/heads/master"));
cl_git_pass(git_transaction_commit(g_tx));
cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, g_repo, "refs/heads/master"));
}
void test_refs_transactions__single_create(void)
{
git_reference *ref;
const char *name = "refs/heads/new-branch";
git_oid id;
cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, g_repo, name));
cl_git_pass(git_transaction_lock_ref(g_tx, name));
git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
cl_git_pass(git_transaction_set_target(g_tx, name, &id, NULL, NULL));
cl_git_pass(git_transaction_commit(g_tx));
cl_git_pass(git_reference_lookup(&ref, g_repo, name));
cl_assert(!git_oid_cmp(&id, git_reference_target(ref)));
git_reference_free(ref);
}
void test_refs_transactions__unlocked_set(void)
{
git_oid id;
cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master"));
git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
cl_git_fail_with(GIT_ENOTFOUND, git_transaction_set_target(g_tx, "refs/heads/foo", &id, NULL, NULL));
cl_git_pass(git_transaction_commit(g_tx));
}
void test_refs_transactions__error_on_locking_locked_ref(void)
{
git_oid id;
git_transaction *g_tx_with_lock;
git_repository *g_repo_with_locking_tx;
const char *g_repo_path = git_repository_path(g_repo);
/* prepare a separate transaction in another instance of testrepo and lock master */
cl_git_pass(git_repository_open(&g_repo_with_locking_tx, g_repo_path));
cl_git_pass(git_transaction_new(&g_tx_with_lock, g_repo_with_locking_tx));
cl_git_pass(git_transaction_lock_ref(g_tx_with_lock, "refs/heads/master"));
/* lock reference for set_target */
cl_git_pass(git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"));
cl_git_fail_with(GIT_ELOCKED, git_transaction_lock_ref(g_tx, "refs/heads/master"));
cl_git_fail_with(GIT_ENOTFOUND, git_transaction_set_target(g_tx, "refs/heads/master", &id, NULL, NULL));
git_transaction_free(g_tx_with_lock);
git_repository_free(g_repo_with_locking_tx);
}
void test_refs_transactions__commit_unlocks_unmodified_ref(void)
{
git_transaction *second_tx;
cl_git_pass(git_transaction_new(&second_tx, g_repo));
cl_git_pass(git_transaction_lock_ref(second_tx, "refs/heads/master"));
cl_git_pass(git_transaction_commit(second_tx));
/* a transaction must now be able to get the lock */
cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master"));
git_transaction_free(second_tx);
}
void test_refs_transactions__free_unlocks_unmodified_ref(void)
{
git_transaction *second_tx;
cl_git_pass(git_transaction_new(&second_tx, g_repo));
cl_git_pass(git_transaction_lock_ref(second_tx, "refs/heads/master"));
git_transaction_free(second_tx);
/* a transaction must now be able to get the lock */
cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master"));
}
+54
View File
@@ -0,0 +1,54 @@
#include "clar_libgit2.h"
static git_repository *repo;
void test_refs_unicode__initialize(void)
{
repo = cl_git_sandbox_init("testrepo.git");
}
void test_refs_unicode__cleanup(void)
{
cl_git_sandbox_cleanup();
repo = NULL;
}
void test_refs_unicode__create_and_lookup(void)
{
git_reference *ref0, *ref1, *ref2;
git_repository *repo2;
const char *REFNAME = "refs/heads/" "\303\205" "ngstr" "\303\266" "m";
const char *master = "refs/heads/master";
/* Create the reference */
cl_git_pass(git_reference_lookup(&ref0, repo, master));
cl_git_pass(git_reference_create(
&ref1, repo, REFNAME, git_reference_target(ref0), 0, NULL));
cl_assert_equal_s(REFNAME, git_reference_name(ref1));
git_reference_free(ref0);
/* Lookup the reference in a different instance of the repository */
cl_git_pass(git_repository_open(&repo2, "testrepo.git"));
cl_git_pass(git_reference_lookup(&ref2, repo2, REFNAME));
cl_assert_equal_oid(git_reference_target(ref1), git_reference_target(ref2));
cl_assert_equal_s(REFNAME, git_reference_name(ref2));
git_reference_free(ref2);
#if GIT_USE_ICONV
/* Lookup reference by decomposed unicode name */
#define REFNAME_DECOMPOSED "refs/heads/" "A" "\314\212" "ngstro" "\314\210" "m"
cl_git_pass(git_reference_lookup(&ref2, repo2, REFNAME_DECOMPOSED));
cl_assert_equal_oid(git_reference_target(ref1), git_reference_target(ref2));
cl_assert_equal_s(REFNAME, git_reference_name(ref2));
git_reference_free(ref2);
#endif
/* Cleanup */
git_reference_free(ref1);
git_repository_free(repo2);
}
+26
View File
@@ -0,0 +1,26 @@
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *g_repo;
void test_refs_update__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
}
void test_refs_update__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_update__updating_the_target_of_a_symref_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
git_reference *head;
cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE));
cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head));
git_reference_free(head);
cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_create(&head, g_repo, GIT_HEAD_FILE, "refs/heads/inv@{id", 1, NULL));
}