lms/vendor/brianium/paratest/src/WrapperRunner/SuiteLoader.php
2025-12-15 12:26:23 +01:00

218 lines
7.2 KiB
PHP

<?php
declare(strict_types=1);
namespace ParaTest\WrapperRunner;
use Generator;
use ParaTest\Options;
use PHPUnit\Event\Facade as EventFacade;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\Extension\ExtensionBootstrapper;
use PHPUnit\Runner\Extension\Facade as ExtensionFacade;
use PHPUnit\Runner\Extension\PharLoader;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Runner\ResultCache\DefaultResultCache;
use PHPUnit\Runner\ResultCache\NullResultCache;
use PHPUnit\Runner\TestSuiteSorter;
use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade;
use PHPUnit\TextUI\Command\Result;
use PHPUnit\TextUI\Command\WarmCodeCoverageCacheCommand;
use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry;
use PHPUnit\TextUI\Configuration\PhpHandler;
use PHPUnit\TextUI\Configuration\TestSuiteBuilder;
use PHPUnit\TextUI\TestSuiteFilterProcessor;
use ReflectionClass;
use ReflectionProperty;
use Symfony\Component\Console\Output\OutputInterface;
use function array_keys;
use function assert;
use function count;
use function is_int;
use function is_string;
use function mt_srand;
use function ob_get_clean;
use function ob_start;
use function preg_quote;
use function sprintf;
use function str_starts_with;
use function strlen;
use function substr;
/** @internal */
final readonly class SuiteLoader
{
public int $testCount;
/** @var list<non-empty-string> */
public array $tests;
public function __construct(
private Options $options,
OutputInterface $output,
CodeCoverageFilterRegistry $codeCoverageFilterRegistry,
) {
(new PhpHandler())->handle($this->options->configuration->php());
if ($this->options->configuration->hasBootstrap()) {
$bootstrapFilename = $this->options->configuration->bootstrap();
include_once $bootstrapFilename;
EventFacade::emitter()->testRunnerBootstrapFinished($bootstrapFilename);
}
if (! $this->options->configuration->noExtensions()) {
if ($this->options->configuration->hasPharExtensionDirectory()) {
(new PharLoader())->loadPharExtensionsInDirectory(
$this->options->configuration->pharExtensionDirectory(),
);
}
$extensionFacade = new ExtensionFacade();
$extensionBootstrapper = new ExtensionBootstrapper(
$this->options->configuration,
$extensionFacade,
);
foreach ($this->options->configuration->extensionBootstrappers() as $bootstrapper) {
$extensionBootstrapper->bootstrap(
$bootstrapper['className'],
$bootstrapper['parameters'],
);
}
}
TestResultFacade::init();
EventFacade::instance()->seal();
$testSuite = (new TestSuiteBuilder())->build($this->options->configuration);
if ($this->options->configuration->executionOrder() === TestSuiteSorter::ORDER_RANDOMIZED) {
mt_srand($this->options->configuration->randomOrderSeed());
}
if (
$this->options->configuration->executionOrder() !== TestSuiteSorter::ORDER_DEFAULT ||
$this->options->configuration->executionOrderDefects() !== TestSuiteSorter::ORDER_DEFAULT ||
$this->options->configuration->resolveDependencies()
) {
$resultCache = new NullResultCache();
if ($this->options->configuration->cacheResult()) {
$resultCache = new DefaultResultCache($this->options->configuration->testResultCacheFile());
$resultCache->load();
}
(new TestSuiteSorter($resultCache))->reorderTestsInSuite(
$testSuite,
$this->options->configuration->executionOrder(),
$this->options->configuration->resolveDependencies(),
$this->options->configuration->executionOrderDefects(),
);
}
(new TestSuiteFilterProcessor())->process($this->options->configuration, $testSuite);
$this->testCount = count($testSuite);
$files = [];
$tests = [];
foreach ($this->loadFiles($testSuite) as $file => $test) {
$files[$file] = null;
if ($test instanceof PhptTestCase) {
$tests[] = $file;
} else {
$name = $test->name();
if ($test->providedData() !== []) {
$dataName = $test->dataName();
if ($this->options->functional) {
$name = sprintf('/%s%s$/', preg_quote($name, '/'), preg_quote($test->dataSetAsString(), '/'));
} else {
if (is_int($dataName)) {
$name .= '#' . $dataName;
} else {
$name .= '@' . $dataName;
}
}
} else {
$name = sprintf('/%s$/', $name);
}
$tests[] = "$file\0$name";
}
}
$this->tests = $this->options->functional
? $tests
: array_keys($files);
if (! $this->options->configuration->hasCoverageReport()) {
return;
}
ob_start();
$result = (new WarmCodeCoverageCacheCommand(
$this->options->configuration,
$codeCoverageFilterRegistry,
))->execute();
$ob_get_clean = ob_get_clean();
assert($ob_get_clean !== false);
$output->write($ob_get_clean);
$output->write($result->output());
if ($result->shellExitCode() !== Result::SUCCESS) {
exit($result->shellExitCode());
}
}
/** @return Generator<non-empty-string, (PhptTestCase|TestCase)> */
private function loadFiles(TestSuite $testSuite): Generator
{
foreach ($testSuite as $test) {
if ($test instanceof TestSuite) {
yield from $this->loadFiles($test);
continue;
}
if ($test instanceof PhptTestCase) {
$refProperty = new ReflectionProperty(PhptTestCase::class, 'filename');
$filename = $refProperty->getValue($test);
assert(is_string($filename) && $filename !== '');
$filename = $this->stripCwd($filename);
yield $filename => $test;
continue;
}
if ($test instanceof TestCase) {
$refClass = new ReflectionClass($test);
$filename = $refClass->getFileName();
assert(is_string($filename));
$filename = $this->stripCwd($filename);
yield $filename => $test;
continue;
}
}
}
/**
* @param non-empty-string $filename
*
* @return non-empty-string
*/
private function stripCwd(string $filename): string
{
if (! str_starts_with($filename, $this->options->cwd)) {
return $filename;
}
$substr = substr($filename, 1 + strlen($this->options->cwd));
assert($substr !== '');
return $substr;
}
}