<?php
declare(strict_types=1);
namespace Tests\git2;
use git2\git;
use git2\git_checkout_options;
use git2\git_index;
use git2\git_merge_analysis_t;
use git2\git_merge_file_favor_t;
use git2\git_merge_file_flag_t;
use git2\git_merge_file_input;
use git2\git_merge_file_options;
use git2\git_merge_file_result;
use git2\git_merge_flag_t;
use git2\git_merge_options;
use git2\git_oidarray;
use git2\git_repository_state_t;
use git2\git_reset_t;
final class MergeTest extends GitTestCase
{
public function testMerge(): void
{
$dir = $this->mkdir('merge');
git::repository_init($repo, $dir, false);
git::signature_new($sig, 'John Doe', 'john.doe@example.com', 1640263000, 60);
git::repository_index($index, $repo);
file_put_contents($dir . '/foo', 'foo');
git::index_add_bypath($index, 'foo');
git::index_write_tree($treeId, $index);
git::tree_lookup($tree, $repo, $treeId);
git::commit_create_v($id1, $repo, 'HEAD', $sig, $sig, null, "A", $tree);
git::commit_lookup($commit1, $repo, $id1);
git::branch_create($b1, $repo, 'b1', $commit1, false);
file_put_contents($dir . '/bar', 'bar');
git::index_add_bypath($index, 'bar');
git::index_write_tree($treeId, $index);
git::tree_lookup($tree, $repo, $treeId);
git::commit_create_v($id2, $repo, null, $sig, $sig, null, "B", $tree, $commit1);
git::commit_lookup($commit2, $repo, $id2);
git::branch_create($b2, $repo, 'b2', $commit2, false);
$this->assertOK(git::checkout_options_init($checkoutOpts, git_checkout_options::VERSION));
git::repository_set_head($repo, 'refs/heads/b1');
$this->assertOK(git::reset($repo, $commit1, git_reset_t::HARD, $checkoutOpts));
git::annotated_commit_from_revspec($ref, $repo, 'refs/heads/b2');
$this->assertOK(git::merge_analysis($analysisOut, $preferenceOut, $repo, [$ref]));
$this->assertSame(git_merge_analysis_t::NORMAL | git_merge_analysis_t::FASTFORWARD, $analysisOut);
$this->assertSame(0, $preferenceOut);
$this->assertOK(git::reference_lookup($head, $repo, 'refs/heads/b1'));
$this->assertOK(git::merge_analysis_for_ref($analysisOut, $preferenceOut, $repo, $head, [$ref]));
$this->assertSame(git_merge_analysis_t::NORMAL | git_merge_analysis_t::FASTFORWARD, $analysisOut);
$this->assertSame(0, $preferenceOut);
$this->assertFileDoesNotExist($dir . '/bar');
$this->assertOK(git::merge_options_init($mergeOpts, git_merge_options::VERSION));
$this->assertOK(git::merge($repo, [$ref], $mergeOpts, $checkoutOpts));
$this->assertSame(git_repository_state_t::MERGE, git::repository_state($repo));
$this->assertFalse(git::index_has_conflicts($index));
$this->assertFileExists($dir . '/bar');
$this->assertOK(git::merge_base($base, $repo, $id1, $id2));
$this->assertSame('1edb9fa8bc346ffbae31fa3ff07205e45705bfff', git::oid_tostr_s($base));
$this->assertOK(git::merge_base_many($baseMany, $repo, [$id1, $id2]));
$this->assertSame('1edb9fa8bc346ffbae31fa3ff07205e45705bfff', git::oid_tostr_s($baseMany));
$this->assertOK(git::merge_base_octopus($baseOctopus, $repo, [$id1, $id2]));
$this->assertSame('1edb9fa8bc346ffbae31fa3ff07205e45705bfff', git::oid_tostr_s($baseOctopus));
$this->assertOK(git::merge_bases($bases, $repo, $id1, $id2));
$this->assertInstanceOf(git_oidarray::class, $bases);
$this->assertCount(1, $bases);
$this->assertSame('1edb9fa8bc346ffbae31fa3ff07205e45705bfff', git::oid_tostr_s($bases[0]));
$this->assertOK(git::merge_bases_many($bases, $repo, [$id1, $id2]));
$this->assertInstanceOf(git_oidarray::class, $bases);
$this->assertCount(1, $bases);
$this->assertSame('1edb9fa8bc346ffbae31fa3ff07205e45705bfff', git::oid_tostr_s($bases[0]));
$this->assertOK(git::merge_commits($mergeCommits, $repo, $commit1, $commit2, $mergeOpts));
$this->assertInstanceOf(git_index::class, $mergeCommits);
$this->assertSame(2, git::index_entrycount($mergeCommits));
}
public function testMergeFile(): void
{
$this->assertOK(git::merge_file_input_init($a, git_merge_file_input::VERSION));
$this->assertInstanceOf(git_merge_file_input::class, $a);
$this->assertSame(git_merge_file_input::VERSION, $a->version);
$this->assertSame(0, $a->size);
$this->assertNull($a->path);
$this->assertSame(0, $a->mode);
$this->assertNull($a->contents);
$a->mode = 0644;
$a->path = 'foo';
$a->contents = "a\nc\n";
$this->assertSame(0644, $a->mode);
$this->assertSame('foo', $a->path);
$this->assertSame(4, $a->size);
$this->assertSame("a\nc\n", $a->contents);
$this->assertOK(git::merge_file_input_init($b, git_merge_file_input::VERSION));
$this->assertInstanceOf(git_merge_file_input::class, $b);
$b->mode = 0644;
$b->path = 'foo';
$b->contents = "a\nb\nc\n";
$this->assertOK(git::merge_file_input_init($c, git_merge_file_input::VERSION));
$this->assertInstanceOf(git_merge_file_input::class, $c);
$c->mode = 0644;
$c->path = 'foo';
$c->contents = "a\nc\nd\n";
$this->assertOK(git::merge_file($result, $a, $b, $c, null));
$this->assertInstanceOf(git_merge_file_result::class, $result);
$this->assertTrue($result->automergeable);
$this->assertSame(0644, $result->mode);
$this->assertSame('foo', $result->path);
$this->assertSame("a\nb\nc\nd\n", $result->contents);
}
public function testMergeFileFromIndex(): void
{
$dir = $this->mkdir('merge_file_from_index');
git::repository_init($repo, $dir, false);
git::repository_index($index, $repo);
file_put_contents($dir . '/a', "a\nc\n");
file_put_contents($dir . '/b', "a\nb\nc\n");
file_put_contents($dir . '/c', "a\nc\nd\n");
$this->assertOK(git::index_add_bypath($index, 'a'));
$this->assertOK(git::index_add_bypath($index, 'b'));
$this->assertOK(git::index_add_bypath($index, 'c'));
$this->assertNotNull($a = git::index_get_bypath($index, 'a', 0));
$this->assertNotNull($b = git::index_get_bypath($index, 'b', 0));
$this->assertNotNull($c = git::index_get_bypath($index, 'c', 0));
$this->assertOK(git::merge_file_from_index($result, $repo, $a, $b, $c, null));
$this->assertInstanceOf(git_merge_file_result::class, $result);
$this->assertSame("a\nb\nc\nd\n", $result->contents);
$this->assertNull($result->path);
}
public function testMergeTrees(): void
{
$dir = $this->mkdir('merge_trees');
git::repository_init($repo, $dir, false);
git::repository_index($index, $repo);
file_put_contents($dir . '/foo', "a\n");
file_put_contents($dir . '/bar', "b\n");
git::index_add_bypath($index, 'foo');
git::index_write_tree($treeId, $index);
git::tree_lookup($tree, $repo, $treeId);
git::tree_dup($dup, $tree);
git::index_add_bypath($index, 'bar');
git::index_write_tree($treeId2, $index);
git::tree_lookup($tree2, $repo, $treeId2);
$this->assertOK(git::merge_trees($result, $repo, null, $tree, $tree2, null));
$this->assertInstanceOf(git_index::class, $result);
$this->assertSame(2, git::index_entrycount($result));
}
public function testMergeFileOpts(): void
{
$this->assertOK(git::merge_file_options_init($opts, git_merge_file_options::VERSION));
$this->assertInstanceOf(git_merge_file_options::class, $opts);
$this->assertSame(git_merge_file_options::VERSION, $opts->version);
$this->assertSame(0, $opts->flags);
$this->assertSame(0, $opts->marker_size);
$this->assertNull($opts->ancestor_label);
$this->assertNull($opts->our_label);
$this->assertNull($opts->their_label);
$this->assertSame(git_merge_file_favor_t::NORMAL, $opts->favor);
$opts->flags |= git_merge_file_flag_t::IGNORE_WHITESPACE;
$opts->marker_size = 100;
$opts->ancestor_label = 'ancestor';
$opts->our_label = 'our';
$opts->their_label = 'their';
$opts->favor = git_merge_file_favor_t::UNION;
$this->assertSame(git_merge_file_flag_t::IGNORE_WHITESPACE, $opts->flags);
$this->assertSame(100, $opts->marker_size);
$this->assertSame('ancestor', $opts->ancestor_label);
$this->assertSame('our', $opts->our_label);
$this->assertSame('their', $opts->their_label);
$this->assertSame(git_merge_file_favor_t::UNION, $opts->favor);
$opts->ancestor_label = null;
$this->assertNull($opts->ancestor_label);
$opts->ancestor_label = '';
$this->assertSame('', $opts->ancestor_label);
}
public function testMergeOpts(): void
{
$this->assertOK(git::merge_options_init($opts, git_merge_options::VERSION));
$this->assertInstanceOf(git_merge_options::class, $opts);
$this->assertSame(git_merge_options::VERSION, $opts->version);
$this->assertSame(git_merge_flag_t::FIND_RENAMES, $opts->flags);
$this->assertSame(0, $opts->rename_threshold);
$this->assertSame(0, $opts->target_limit);
$this->assertSame(0, $opts->recursion_limit);
$this->assertSame(0, $opts->file_flags);
$this->assertNull($opts->metric);
$this->assertNull($opts->default_driver);
$this->assertSame(git_merge_file_favor_t::NORMAL, $opts->file_favor);
$opts->flags |= git_merge_flag_t::FAIL_ON_CONFLICT;
$opts->rename_threshold = 1;
$opts->target_limit = 2;
$opts->recursion_limit = 3;
$opts->file_flags = git_merge_file_flag_t::IGNORE_WHITESPACE;
$opts->file_favor = git_merge_file_favor_t::UNION;
$this->assertSame(git_merge_flag_t::FIND_RENAMES | git_merge_flag_t::FAIL_ON_CONFLICT, $opts->flags);
$this->assertSame(1, $opts->rename_threshold);
$this->assertSame(2, $opts->target_limit);
$this->assertSame(3, $opts->recursion_limit);
$this->assertSame(git_merge_file_flag_t::IGNORE_WHITESPACE, $opts->file_flags);
$this->assertSame(git_merge_file_favor_t::UNION, $opts->file_favor);
}
}