<?php

declare(strict_types=1);
namespace Tests\git2;
use git2\git;
use git2\git_delta_t;
use git2\git_diff_delta;
use git2\git_diff_hunk;
use git2\git_diff_line;

final class PatchTest extends GitTestCase
{

	public function testFromBlobAndBuffer(): void
	{
		$dir = $this->mkdir('from_blob_and_buffer');
		git::repository_init($repo, $dir, false);
		git::blob_create_from_buffer($id, $repo, 'foo');
		git::blob_lookup($blob, $repo, $id);

		$this->assertOK(git::patch_from_blob_and_buffer($patch, $blob, 'foo', 'bar', 'bar', null));
		$this->assertOK(git::patch_to_buf($buf, $patch));
		$this->assertStringEqualsFile(__DIR__ . '/fixtures/patch.foo.patch', (string) $buf);

		$this->assertOK(git::patch_line_stats($context, $additions, $deletions, $patch));
		$this->assertSame(0, $context);
		$this->assertSame(1, $additions);
		$this->assertSame(1, $deletions);

		$this->assertSame(151, git::patch_size($patch, true, true, true));

		$delta = git::patch_get_delta($patch);
		$this->assertSame(git_delta_t::MODIFIED, $delta->status);

		$this->assertOK(git::patch_get_hunk($hunk, $linesInHunk, $patch, 0));
		$this->assertInstanceOf(git_diff_hunk::class, $hunk);

		$this->assertOK(git::patch_get_line_in_hunk($line, $patch, 0, 1));
		$this->assertInstanceOf(git_diff_line::class, $line);

		$this->assertSame(1, git::patch_num_hunks($patch));
		$this->assertSame(4, git::patch_num_lines_in_hunk($patch, 0));

		$this->assertOK(git::patch_from_blob_and_buffer($patch, null, null, 'bar', null, null));
		$this->assertOK(git::patch_to_buf($buf2, $patch));
		$this->assertStringEqualsFile(__DIR__ . '/fixtures/patch.bar.patch', (string) $buf2);

		$this->assertOK(git::patch_from_blob_and_buffer($patch, null, null, null, null, null));
		$this->assertNull(git::patch_owner($patch));
	}

	public function testFromBlobs(): void
	{
		$dir = $this->mkdir('from_blob_and_buffer');
		git::repository_init($repo, $dir, false);
		git::blob_create_from_buffer($idf, $repo, 'foo');
		git::blob_create_from_buffer($idb, $repo, 'bar');

		git::blob_lookup($foo, $repo, $idf);
		git::blob_lookup($bar, $repo, $idb);

		$this->assertOK(git::patch_from_blobs($patch, $foo, 'foo', $bar, 'bar', null));
		git::patch_line_stats($context, $additions, $deletions, $patch);

		$this->assertSame(0, $context);
		$this->assertSame(1, $additions);
		$this->assertSame(1, $deletions);
	}

	public function testFromBuffers(): void
	{
		$this->assertOK(git::patch_from_buffers($patch, 'foo', 'foo', 'bar', 'bar', null));
		git::patch_line_stats($context, $additions, $deletions, $patch);

		$this->assertSame(0, $context);
		$this->assertSame(1, $additions);
		$this->assertSame(1, $deletions);
	}

	public function testFromDiff(): void
	{
		git::diff_from_buffer($diff, file_get_contents(__DIR__ . '/fixtures/diff.foo.patch'));
		$this->assertOK(git::patch_from_diff($patch, $diff, 0));

		git::patch_line_stats($context, $additions, $deletions, $patch);

		$this->assertSame(0, $context);
		$this->assertSame(1, $additions);
		$this->assertSame(0, $deletions);
	}

	public function testPrint(): void
	{
		git::patch_from_blob_and_buffer($patch, null, null, 'bar', null, null);

		$calls = [];

		$this->assertOK(git::patch_print($patch, function(git_diff_delta $delta, ?git_diff_hunk $hunk, git_diff_line $line) use(&$calls): void {
			$calls[] = [
				$delta->status,
				$hunk?->header,
				$line->num_lines,
			];
		}));

		$this->assertSame([
			[git_delta_t::ADDED, null, 1],
			[git_delta_t::ADDED, "@@ -0,0 +1 @@\n", 1],
			[git_delta_t::ADDED, "@@ -0,0 +1 @@\n", 0],
			[git_delta_t::ADDED, "@@ -0,0 +1 @@\n", 2],
		], $calls);
	}

}