<?php

declare(strict_types=1);

namespace Tests\Codeception\Task\Splitter;

use Codeception\Task\Splitter\SplitTestsByTimeTask;
use Codeception\Task\Splitter\TestsSplitterTrait;
use Consolidation\Log\Logger;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Finder\Finder;
use const Tests\Codeception\Task\TEST_PATH;

/**
 * Class SplitTestsByTimeTaskTest
 *
 * @coversDefaultClass \Codeception\Task\Splitter\SplitTestsByTimeTask
 */
final class SplitTestsByTimeTaskTest extends TestCase
{
    use TestsSplitterTrait;

    /**
     * @testdox splitting the tests by execution time
     * @covers ::run
     */
    public function testRun(): void
    {
        $expectedGroupContent = [
            'group_1' => [ // 150 sec. + 20 sec. = 170 sec.
                'tests/fixtures/DependencyResolutionExampleTests/DirA/Example1Test.php:testA',
                'tests/fixtures/DependencyResolutionExampleTests2/DirA/Example1Test.php:testB',
            ],
            'group_2' => [ // 130 sec. + 20 sec. + 10 sec. = 160 sec.
                'tests/fixtures/DependencyResolutionExampleTests/DirA/Example1Test.php:testB',
                'tests/fixtures/Cests/DirB/ExampleACest.php:testExampleGoFrom',
                'tests/fixtures/DependencyResolutionExampleTests/DirA/Example1Test.php:testC',
            ],
            'group_3' => [ // 120.10 sec. + 29.98 sec. + 0.5 sec. + 1.5 sec. + 0.3 sec. = 152.38 sec.
                'tests/fixtures/Cests/DirC/ExampleACest.php:testExampleStayHere',
                'tests/fixtures/Cests/DirA/ExampleACest.php:testExampleGoTo',
                'tests/fixtures/Unit/ExampleBTest.php:testB',
                'tests/fixtures/Unit/ExampleBTest.php:testA',
                'tests/fixtures/Unit/ExampleATest.php:testB',
            ],
            'group_4' => [ // 34 sec. + 35 sec. + 33 sec. + 30 sec. + 20 sec. + 0.3 sec. = 152.3 sec.
                'tests/fixtures/DependencyResolutionExampleTests/DirA/Example2Test.php:testD',
                'tests/fixtures/DependencyResolutionExampleTests/DirA/Example2Test.php:testE',
                'tests/fixtures/DependencyResolutionExampleTests/DirB/Example3Test.php:testF',
                'tests/fixtures/DependencyResolutionExampleTests/DirB/Example3Test.php:testG',
                'tests/fixtures/DependencyResolutionExampleTests2/DirA/Example1Test.php:testA',
                'tests/fixtures/Unit/ExampleATest.php:testA',
            ],
        ];

        $expectedFiles = 4;

        $task = $this->getMockBuilder(SplitTestsByTimeTask::class)
            ->setConstructorArgs([4])
            ->onlyMethods(['getProjectDir'])
            ->getMock();

        $task->method('getProjectDir')->willReturn(dirname(TEST_PATH));
        $groupTo = TEST_PATH . '/result/group_';
        $task->setLogger(new Logger(new NullOutput()));
        $task->statFile(TEST_PATH . '/fixtures/timeReport.json')
            ->projectRoot(TEST_PATH . '/../')
            ->testsFrom(TEST_PATH . '/fixtures/')
            ->groupsTo($groupTo)
            ->run();


        for ($i = 1; $i <= $expectedFiles; ++$i) {
            $filename = $groupTo . $i;
            $this->assertFileExists($filename);
            $lines = explode(PHP_EOL, file_get_contents($filename));
            $this->assertCount(count($expectedGroupContent['group_' . $i]), $lines);
            foreach ($expectedGroupContent['group_' . $i] as $expectedSubpath) {
                $matches = preg_grep('~' . preg_quote($expectedSubpath, '~') . '$~', $lines);
                $this->assertCount(
                    1,
                    $matches,
                    sprintf(
                        'Did not found expected subpath %s in lines of file %s.',
                        $expectedSubpath,
                        $filename
                    )
                );
            }
        }

        $this->assertFileDoesNotExist($groupTo . ($expectedFiles + 1));
    }

    protected function tearDown(): void
    {
        parent::tearDown(); // TODO: Change the autogenerated stub
        $finder = Finder::create()
            ->files()
            ->name('group_*');

        foreach ($finder->in(TEST_PATH . '/result') as $file) {
            unlink($file->getPathname());
        }
    }
}
