Blame tests/merge/driver.c

Packit Service 20376f
#include "clar_libgit2.h"
Packit Service 20376f
#include "git2/repository.h"
Packit Service 20376f
#include "git2/merge.h"
Packit Service 20376f
#include "buffer.h"
Packit Service 20376f
#include "merge.h"
Packit Service 20376f
Packit Service 20376f
#define TEST_REPO_PATH "merge-resolve"
Packit Service 20376f
#define BRANCH_ID "7cb63eed597130ba4abb87b3e544b85021905520"
Packit Service 20376f
Packit Service 20376f
#define AUTOMERGEABLE_IDSTR "f2e1550a0c9e53d5811175864a29536642ae3821"
Packit Service 20376f
Packit Service 20376f
static git_repository *repo;
Packit Service 20376f
static git_index *repo_index;
Packit Service 20376f
static git_oid automergeable_id;
Packit Service 20376f
Packit Service 20376f
static void test_drivers_register(void);
Packit Service 20376f
static void test_drivers_unregister(void);
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__initialize(void)
Packit Service 20376f
{
Packit Service 20376f
    git_config *cfg;
Packit Service 20376f
Packit Service 20376f
    repo = cl_git_sandbox_init(TEST_REPO_PATH);
Packit Service 20376f
    git_repository_index(&repo_index, repo);
Packit Service 20376f
Packit Service 20376f
	git_oid_fromstr(&automergeable_id, AUTOMERGEABLE_IDSTR);
Packit Service 20376f
Packit Service 20376f
    /* Ensure that the user's merge.conflictstyle doesn't interfere */
Packit Service 20376f
    cl_git_pass(git_repository_config(&cfg, repo));
Packit Service 20376f
Packit Service 20376f
    cl_git_pass(git_config_set_string(cfg, "merge.conflictstyle", "merge"));
Packit Service 20376f
    cl_git_pass(git_config_set_bool(cfg, "core.autocrlf", false));
Packit Service 20376f
Packit Service 20376f
	test_drivers_register();
Packit Service 20376f
Packit Service 20376f
    git_config_free(cfg);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__cleanup(void)
Packit Service 20376f
{
Packit Service 20376f
	test_drivers_unregister();
Packit Service 20376f
Packit Service 20376f
    git_index_free(repo_index);
Packit Service 20376f
	cl_git_sandbox_cleanup();
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
struct test_merge_driver {
Packit Service 20376f
	git_merge_driver base;
Packit Service 20376f
	int initialized;
Packit Service 20376f
	int shutdown;
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
static int test_driver_init(git_merge_driver *s)
Packit Service 20376f
{
Packit Service 20376f
	struct test_merge_driver *self = (struct test_merge_driver *)s;
Packit Service 20376f
	self->initialized = 1;
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void test_driver_shutdown(git_merge_driver *s)
Packit Service 20376f
{
Packit Service 20376f
	struct test_merge_driver *self = (struct test_merge_driver *)s;
Packit Service 20376f
	self->shutdown = 1;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int test_driver_apply(
Packit Service 20376f
	git_merge_driver *s,
Packit Service 20376f
	const char **path_out,
Packit Service 20376f
	uint32_t *mode_out,
Packit Service 20376f
	git_buf *merged_out,
Packit Service 20376f
	const char *filter_name,
Packit Service 20376f
	const git_merge_driver_source *src)
Packit Service 20376f
{
Packit Service 20376f
	GIT_UNUSED(s);
Packit Service 20376f
	GIT_UNUSED(src);
Packit Service 20376f
Packit Service 20376f
	*path_out = "applied.txt";
Packit Service 20376f
	*mode_out = GIT_FILEMODE_BLOB;
Packit Service 20376f
Packit Service 20376f
	return git_buf_printf(merged_out, "This is the `%s` driver.\n",
Packit Service 20376f
		filter_name);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static struct test_merge_driver test_driver_custom = {
Packit Service 20376f
	{
Packit Service 20376f
		GIT_MERGE_DRIVER_VERSION,
Packit Service 20376f
		test_driver_init,
Packit Service 20376f
		test_driver_shutdown,
Packit Service 20376f
		test_driver_apply,
Packit Service 20376f
	},
Packit Service 20376f
	0,
Packit Service 20376f
	0,
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
static struct test_merge_driver test_driver_wildcard = {
Packit Service 20376f
	{
Packit Service 20376f
		GIT_MERGE_DRIVER_VERSION,
Packit Service 20376f
		test_driver_init,
Packit Service 20376f
		test_driver_shutdown,
Packit Service 20376f
		test_driver_apply,
Packit Service 20376f
	},
Packit Service 20376f
	0,
Packit Service 20376f
	0,
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
static void test_drivers_register(void)
Packit Service 20376f
{
Packit Service 20376f
	cl_git_pass(git_merge_driver_register("custom", &test_driver_custom.base));
Packit Service 20376f
	cl_git_pass(git_merge_driver_register("*", &test_driver_wildcard.base));
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void test_drivers_unregister(void)
Packit Service 20376f
{
Packit Service 20376f
	cl_git_pass(git_merge_driver_unregister("custom"));
Packit Service 20376f
	cl_git_pass(git_merge_driver_unregister("*"));
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void set_gitattributes_to(const char *driver)
Packit Service 20376f
{
Packit Service 20376f
	git_buf line = GIT_BUF_INIT;
Packit Service 20376f
Packit Service 20376f
	if (driver && strcmp(driver, ""))
Packit Service 20376f
		git_buf_printf(&line, "automergeable.txt merge=%s\n", driver);
Packit Service 20376f
	else if (driver)
Packit Service 20376f
		git_buf_printf(&line, "automergeable.txt merge\n");
Packit Service 20376f
	else
Packit Service 20376f
		git_buf_printf(&line, "automergeable.txt -merge\n");
Packit Service 20376f
Packit Service 20376f
	cl_assert(!git_buf_oom(&line));
Packit Service 20376f
Packit Service 20376f
	cl_git_mkfile(TEST_REPO_PATH "/.gitattributes", line.ptr);
Packit Service 20376f
	git_buf_free(&line);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void merge_branch(void)
Packit Service 20376f
{
Packit Service 20376f
	git_oid their_id;
Packit Service 20376f
	git_annotated_commit *their_head;
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_oid_fromstr(&their_id, BRANCH_ID));
Packit Service 20376f
	cl_git_pass(git_annotated_commit_lookup(&their_head, repo, &their_id));
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_head,
Packit Service 20376f
		1, NULL, NULL));
Packit Service 20376f
Packit Service 20376f
	git_annotated_commit_free(their_head);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__custom(void)
Packit Service 20376f
{
Packit Service 20376f
	const char *expected = "This is the `custom` driver.\n";
Packit Service 20376f
	set_gitattributes_to("custom");
Packit Service 20376f
	merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_assert_equal_file(expected, strlen(expected),
Packit Service 20376f
		TEST_REPO_PATH "/applied.txt");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__wildcard(void)
Packit Service 20376f
{
Packit Service 20376f
	const char *expected = "This is the `foobar` driver.\n";
Packit Service 20376f
	set_gitattributes_to("foobar");
Packit Service 20376f
	merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_assert_equal_file(expected, strlen(expected),
Packit Service 20376f
		TEST_REPO_PATH "/applied.txt");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__shutdown_is_called(void)
Packit Service 20376f
{
Packit Service 20376f
    test_driver_custom.initialized = 0;
Packit Service 20376f
    test_driver_custom.shutdown = 0;
Packit Service 20376f
    test_driver_wildcard.initialized = 0;
Packit Service 20376f
    test_driver_wildcard.shutdown = 0;
Packit Service 20376f
    
Packit Service 20376f
    /* run the merge with the custom driver */
Packit Service 20376f
    set_gitattributes_to("custom");
Packit Service 20376f
    merge_branch();
Packit Service 20376f
    
Packit Service 20376f
	/* unregister the drivers, ensure their shutdown function is called */
Packit Service 20376f
	test_drivers_unregister();
Packit Service 20376f
Packit Service 20376f
    /* since the `custom` driver was used, it should have been initialized and
Packit Service 20376f
     * shutdown, but the wildcard driver was not used at all and should not
Packit Service 20376f
     * have been initialized or shutdown.
Packit Service 20376f
     */
Packit Service 20376f
	cl_assert(test_driver_custom.initialized);
Packit Service 20376f
	cl_assert(test_driver_custom.shutdown);
Packit Service 20376f
	cl_assert(!test_driver_wildcard.initialized);
Packit Service 20376f
	cl_assert(!test_driver_wildcard.shutdown);
Packit Service 20376f
Packit Service 20376f
	test_drivers_register();
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int defer_driver_apply(
Packit Service 20376f
	git_merge_driver *s,
Packit Service 20376f
	const char **path_out,
Packit Service 20376f
	uint32_t *mode_out,
Packit Service 20376f
	git_buf *merged_out,
Packit Service 20376f
	const char *filter_name,
Packit Service 20376f
	const git_merge_driver_source *src)
Packit Service 20376f
{
Packit Service 20376f
	GIT_UNUSED(s);
Packit Service 20376f
	GIT_UNUSED(path_out);
Packit Service 20376f
	GIT_UNUSED(mode_out);
Packit Service 20376f
	GIT_UNUSED(merged_out);
Packit Service 20376f
	GIT_UNUSED(filter_name);
Packit Service 20376f
	GIT_UNUSED(src);
Packit Service 20376f
Packit Service 20376f
	return GIT_PASSTHROUGH;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static struct test_merge_driver test_driver_defer_apply = {
Packit Service 20376f
	{
Packit Service 20376f
		GIT_MERGE_DRIVER_VERSION,
Packit Service 20376f
		test_driver_init,
Packit Service 20376f
		test_driver_shutdown,
Packit Service 20376f
		defer_driver_apply,
Packit Service 20376f
	},
Packit Service 20376f
	0,
Packit Service 20376f
	0,
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__apply_can_defer(void)
Packit Service 20376f
{
Packit Service 20376f
	const git_index_entry *idx;
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_merge_driver_register("defer",
Packit Service 20376f
		&test_driver_defer_apply.base));
Packit Service 20376f
Packit Service 20376f
    set_gitattributes_to("defer");
Packit Service 20376f
    merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_assert((idx = git_index_get_bypath(repo_index, "automergeable.txt", 0)));
Packit Service 20376f
	cl_assert_equal_oid(&automergeable_id, &idx->id);
Packit Service 20376f
Packit Service 20376f
	git_merge_driver_unregister("defer");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int conflict_driver_apply(
Packit Service 20376f
	git_merge_driver *s,
Packit Service 20376f
	const char **path_out,
Packit Service 20376f
	uint32_t *mode_out,
Packit Service 20376f
	git_buf *merged_out,
Packit Service 20376f
	const char *filter_name,
Packit Service 20376f
	const git_merge_driver_source *src)
Packit Service 20376f
{
Packit Service 20376f
	GIT_UNUSED(s);
Packit Service 20376f
	GIT_UNUSED(path_out);
Packit Service 20376f
	GIT_UNUSED(mode_out);
Packit Service 20376f
	GIT_UNUSED(merged_out);
Packit Service 20376f
	GIT_UNUSED(filter_name);
Packit Service 20376f
	GIT_UNUSED(src);
Packit Service 20376f
Packit Service 20376f
	return GIT_EMERGECONFLICT;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static struct test_merge_driver test_driver_conflict_apply = {
Packit Service 20376f
	{
Packit Service 20376f
		GIT_MERGE_DRIVER_VERSION,
Packit Service 20376f
		test_driver_init,
Packit Service 20376f
		test_driver_shutdown,
Packit Service 20376f
		conflict_driver_apply,
Packit Service 20376f
	},
Packit Service 20376f
	0,
Packit Service 20376f
	0,
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__apply_can_conflict(void)
Packit Service 20376f
{
Packit Service 20376f
	const git_index_entry *ancestor, *ours, *theirs;
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_merge_driver_register("conflict",
Packit Service 20376f
		&test_driver_conflict_apply.base));
Packit Service 20376f
Packit Service 20376f
    set_gitattributes_to("conflict");
Packit Service 20376f
    merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_index_conflict_get(&ancestor, &ours, &theirs,
Packit Service 20376f
		repo_index, "automergeable.txt"));
Packit Service 20376f
Packit Service 20376f
	git_merge_driver_unregister("conflict");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__default_can_be_specified(void)
Packit Service 20376f
{
Packit Service 20376f
	git_oid their_id;
Packit Service 20376f
	git_annotated_commit *their_head;
Packit Service 20376f
	git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT;
Packit Service 20376f
	const char *expected = "This is the `custom` driver.\n";
Packit Service 20376f
Packit Service 20376f
	merge_opts.default_driver = "custom";
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_oid_fromstr(&their_id, BRANCH_ID));
Packit Service 20376f
	cl_git_pass(git_annotated_commit_lookup(&their_head, repo, &their_id));
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_head,
Packit Service 20376f
		1, &merge_opts, NULL));
Packit Service 20376f
Packit Service 20376f
	git_annotated_commit_free(their_head);
Packit Service 20376f
Packit Service 20376f
	cl_assert_equal_file(expected, strlen(expected),
Packit Service 20376f
		TEST_REPO_PATH "/applied.txt");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__honors_builtin_mergedefault(void)
Packit Service 20376f
{
Packit Service 20376f
	const git_index_entry *ancestor, *ours, *theirs;
Packit Service 20376f
Packit Service 20376f
	cl_repo_set_string(repo, "merge.default", "binary");
Packit Service 20376f
	merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_index_conflict_get(&ancestor, &ours, &theirs,
Packit Service 20376f
		repo_index, "automergeable.txt"));
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__honors_custom_mergedefault(void)
Packit Service 20376f
{
Packit Service 20376f
	const char *expected = "This is the `custom` driver.\n";
Packit Service 20376f
Packit Service 20376f
	cl_repo_set_string(repo, "merge.default", "custom");
Packit Service 20376f
	merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_assert_equal_file(expected, strlen(expected),
Packit Service 20376f
		TEST_REPO_PATH "/applied.txt");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__mergedefault_deferring_falls_back_to_text(void)
Packit Service 20376f
{
Packit Service 20376f
	const git_index_entry *idx;
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_merge_driver_register("defer",
Packit Service 20376f
		&test_driver_defer_apply.base));
Packit Service 20376f
Packit Service 20376f
	cl_repo_set_string(repo, "merge.default", "defer");
Packit Service 20376f
	merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_assert((idx = git_index_get_bypath(repo_index, "automergeable.txt", 0)));
Packit Service 20376f
	cl_assert_equal_oid(&automergeable_id, &idx->id);
Packit Service 20376f
Packit Service 20376f
	git_merge_driver_unregister("defer");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__set_forces_text(void)
Packit Service 20376f
{
Packit Service 20376f
	const git_index_entry *idx;
Packit Service 20376f
Packit Service 20376f
	/* `merge` without specifying a driver indicates `text` */
Packit Service 20376f
	set_gitattributes_to("");
Packit Service 20376f
	cl_repo_set_string(repo, "merge.default", "custom");
Packit Service 20376f
Packit Service 20376f
	merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_assert((idx = git_index_get_bypath(repo_index, "automergeable.txt", 0)));
Packit Service 20376f
	cl_assert_equal_oid(&automergeable_id, &idx->id);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__unset_forces_binary(void)
Packit Service 20376f
{
Packit Service 20376f
	const git_index_entry *ancestor, *ours, *theirs;
Packit Service 20376f
Packit Service 20376f
	/* `-merge` without specifying a driver indicates `binary` */
Packit Service 20376f
	set_gitattributes_to(NULL);
Packit Service 20376f
	cl_repo_set_string(repo, "merge.default", "custom");
Packit Service 20376f
Packit Service 20376f
	merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_index_conflict_get(&ancestor, &ours, &theirs,
Packit Service 20376f
		repo_index, "automergeable.txt"));
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_merge_driver__not_configured_driver_falls_back(void)
Packit Service 20376f
{
Packit Service 20376f
	const git_index_entry *idx;
Packit Service 20376f
Packit Service 20376f
	test_drivers_unregister();
Packit Service 20376f
Packit Service 20376f
	/* `merge` without specifying a driver indicates `text` */
Packit Service 20376f
	set_gitattributes_to("notfound");
Packit Service 20376f
Packit Service 20376f
	merge_branch();
Packit Service 20376f
Packit Service 20376f
	cl_assert((idx = git_index_get_bypath(repo_index, "automergeable.txt", 0)));
Packit Service 20376f
	cl_assert_equal_oid(&automergeable_id, &idx->id);
Packit Service 20376f
Packit Service 20376f
	test_drivers_register();
Packit Service 20376f
}
Packit Service 20376f