<?php

declare(strict_types=1);

namespace Tests\Codeception\Task\Extension;

use Codeception\Event\FailEvent;
use Codeception\Task\Extension\FailedTestsReporter;
use PHPUnit\Framework\TestCase;
use SplFileInfo;
use Symfony\Component\Finder\Finder;
use const Tests\Codeception\Task\TEST_PATH;

/**
 * Class FailedTestsReporterTest
 *
 * @coversDefaultClass \Codeception\Task\Extension\FailedTestsReporter
 */
final class FailedTestsReporterTest extends TestCase
{
    private array $failedTests = [
        ['testName' => 'tests/acceptance/bar/baz.php:testA',],
        ['testName' => 'tests/acceptance/bar/baz.php:testB',],
        ['testName' => 'tests/acceptance/bar/baz.php:testC',],
        ['testName' => 'tests/acceptance/bar/baz.php:testD',],
        ['testName' => 'tests/acceptance/bar/baz.php:testE',],
        ['testName' => 'tests/acceptance/bar/baz.php:testF',],
        ['testName' => 'tests/acceptance/bar/baz.php:testG',],
        ['testName' => 'tests/acceptance/bar/baz.php:testH',],
    ];

    /**
     * @covers ::endRun
     */
    public function testEndRun(): void
    {
        $reporter = $this->getMockBuilder(FailedTestsReporter::class)
            ->disableOriginalConstructor()
            ->onlyMethods(['getTestName', 'getLogDir'])
            ->getMock();

        $reporter->method('getLogDir')->willReturn(TEST_PATH . '/result/');

        // prepare Mocks for Test
        $testEvents = [];
        foreach ($this->failedTests as $test) {
            $eventMock = $this->getMockBuilder(FailEvent::class)
                ->disableOriginalConstructor()
                ->getMock();

            $testEvents[] = [
                'mock' => $eventMock,
                'testName' => $test['testName']
            ];
        }

        // get test name by the TestEventMock
        $reporter
            ->method('getTestName')
            ->withConsecutive(
                ...array_map(
                    static function (FailEvent $event): array {
                        return [$event];
                    },
                    array_column($testEvents, 'mock')
                )
            )
            ->willReturnOnConsecutiveCalls(...array_column($testEvents, 'testName'));

        foreach ($testEvents as $event) {
            $reporter->afterFail($event['mock']);
        }

        $reporter->endRun();
        $files = Finder::create()
            ->followLinks()
            ->files()
            ->in(TEST_PATH)
            ->path('result')
            ->name('/^failedTests_\w+\.\w+\.txt$/');

        $iterator = $files->getIterator();
        $this->assertCount(1, $iterator);
        $iterator->rewind();
        /** @var SplFileInfo $file */
        $file = $iterator->current();
        $this->assertTrue($file->isFile());
        $content = explode(PHP_EOL, file_get_contents($file->getPathname()));
        $this->assertCount(8, $content);
    }

    protected function tearDown(): void
    {
        parent::tearDown(); // TODO: Change the autogenerated stub
        $files = Finder::create()
            ->followLinks()
            ->files()
            ->in(TEST_PATH)
            ->path('result')
            ->name('/^failedTests_\w+\.\w+\.txt$/');

        foreach ($files->getIterator() as $file) {
            unlink($file->getPathname());
        }
    }
}
