diff --git a/overrides/Event/Value/ThrowableBuilder.php b/overrides/Event/Value/ThrowableBuilder.php index 38ff3757..fca7dd9e 100644 --- a/overrides/Event/Value/ThrowableBuilder.php +++ b/overrides/Event/Value/ThrowableBuilder.php @@ -1,5 +1,37 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace PHPUnit\Runner\Filter; -use Exception; -use Pest\Contracts\HasPrintableTestCaseName; -use PHPUnit\Framework\SelfDescribing; use PHPUnit\Framework\Test; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; @@ -44,30 +52,41 @@ use RecursiveFilterIterator; use RecursiveIterator; use function end; -use function implode; use function preg_match; -use function sprintf; -use function str_replace; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ -final class NameFilterIterator extends RecursiveFilterIterator +abstract class NameFilterIterator extends RecursiveFilterIterator { - private ?string $filter = null; - - private ?int $filterMin = null; - - private ?int $filterMax = null; + /** + * @psalm-var non-empty-string + */ + private readonly string $regularExpression; /** - * @throws Exception + * @psalm-var ?int + */ + private readonly ?int $dataSetMinimum; + + /** + * @psalm-var ?int + */ + private readonly ?int $dataSetMaximum; + + /** + * @psalm-param RecursiveIterator $iterator + * @psalm-param non-empty-string $filter */ public function __construct(RecursiveIterator $iterator, string $filter) { parent::__construct($iterator); - $this->setFilter($filter); + $preparedFilter = $this->prepareFilter($filter); + + $this->regularExpression = $preparedFilter['regularExpression']; + $this->dataSetMinimum = $preparedFilter['dataSetMinimum']; + $this->dataSetMaximum = $preparedFilter['dataSetMaximum']; } public function accept(): bool @@ -78,95 +97,26 @@ final class NameFilterIterator extends RecursiveFilterIterator return true; } - $tmp = $this->describe($test); - - if ($tmp[0] !== '') { - $name = implode('::', $tmp); - } else { - $name = $tmp[1]; + if (! $test instanceof TestCase) { + return false; } - $accepted = @preg_match($this->filter, $name, $matches); + $name = $test::class.'::'.$test->nameWithDataSet(); - if ($accepted && isset($this->filterMax)) { + $accepted = @preg_match($this->regularExpression, $name, $matches) === 1; + + if ($accepted && isset($this->dataSetMaximum)) { $set = end($matches); - $accepted = $set >= $this->filterMin && $set <= $this->filterMax; + $accepted = $set >= $this->dataSetMinimum && $set <= $this->dataSetMaximum; } - return (bool) $accepted; + return $accepted; } /** - * @throws Exception + * @psalm-param non-empty-string $filter + * + * @psalm-return array{regularExpression: non-empty-string, dataSetMinimum: ?int, dataSetMaximum: ?int} */ - private function setFilter(string $filter): void - { - if (@preg_match($filter, '') === false) { - // Handles: - // * testAssertEqualsSucceeds#4 - // * testAssertEqualsSucceeds#4-8 - if (preg_match('/^(.*?)#(\d+)(?:-(\d+))?$/', $filter, $matches)) { - if (isset($matches[3]) && $matches[2] < $matches[3]) { - $filter = sprintf( - '%s.*with dataset #(\d+)$', - $matches[1] - ); - - $this->filterMin = (int) $matches[2]; - $this->filterMax = (int) $matches[3]; - } else { - $filter = sprintf( - '%s.*with dataset #%s$', - $matches[1], - $matches[2] - ); - } - } // Handles: - // * testDetermineJsonError@JSON_ERROR_NONE - // * testDetermineJsonError@JSON.* - elseif (preg_match('/^(.*?)@(.+)$/', $filter, $matches)) { - $filter = sprintf( - '%s.*with dataset "%s"$', - $matches[1], - $matches[2] - ); - } - - // Escape delimiters in regular expression. Do NOT use preg_quote, - // to keep magic characters. - $filter = sprintf( - '/%s/i', - str_replace( - '/', - '\\/', - $filter - ) - ); - } - - $this->filter = $filter; - } - - /** - * @psalm-return array{0: string, 1: string} - */ - private function describe(Test $test): array - { - if ($test instanceof HasPrintableTestCaseName) { - return [ - $test::getPrintableTestCaseName(), - $test->getPrintableTestCaseMethodName(), - ]; - } - - if ($test instanceof TestCase) { - return [$test::class, $test->nameWithDataSet()]; - } - - if ($test instanceof SelfDescribing) { - return ['', $test->toString()]; - } - - return ['', $test::class]; - } + abstract protected function prepareFilter(string $filter): array; } diff --git a/overrides/Runner/ResultCache/DefaultResultCache.php b/overrides/Runner/ResultCache/DefaultResultCache.php index 49b9e467..b798351d 100644 --- a/overrides/Runner/ResultCache/DefaultResultCache.php +++ b/overrides/Runner/ResultCache/DefaultResultCache.php @@ -81,11 +81,6 @@ final class DefaultResultCache implements ResultCache */ private array $defects = []; - /** - * @psalm-var array - */ - private array $currentDefects = []; - /** * @psalm-var array */ @@ -102,10 +97,11 @@ final class DefaultResultCache implements ResultCache public function setStatus(string $id, TestStatus $status): void { - if ($status->isFailure() || $status->isError()) { - $this->currentDefects[$id] = $status; - $this->defects[$id] = $status; + if ($status->isSuccess()) { + return; } + + $this->defects[$id] = $status; } public function status(string $id): TestStatus @@ -115,10 +111,6 @@ final class DefaultResultCache implements ResultCache public function setTime(string $id, float $time): void { - if (! isset($this->currentDefects[$id])) { - unset($this->defects[$id]); - } - $this->times[$id] = $time; } @@ -135,7 +127,7 @@ final class DefaultResultCache implements ResultCache $data = json_decode( file_get_contents($this->cacheFilename), - true + true, ); if ($data === null) { @@ -183,7 +175,7 @@ final class DefaultResultCache implements ResultCache file_put_contents( $this->cacheFilename, json_encode($data), - LOCK_EX + LOCK_EX, ); } diff --git a/overrides/TextUI/Command/WarmCodeCoverageCacheCommand.php b/overrides/TextUI/Command/WarmCodeCoverageCacheCommand.php index 7137b5b8..ad301b54 100644 --- a/overrides/TextUI/Command/WarmCodeCoverageCacheCommand.php +++ b/overrides/TextUI/Command/WarmCodeCoverageCacheCommand.php @@ -45,6 +45,8 @@ declare(strict_types=1); namespace PHPUnit\TextUI\Command; +use const PHP_EOL; + use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; use PHPUnit\TextUI\Configuration\Configuration; use PHPUnit\TextUI\Configuration\NoCoverageCacheDirectoryException; @@ -55,11 +57,11 @@ use SebastianBergmann\Timer\Timer; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ -final class WarmCodeCoverageCacheCommand implements Command +final readonly class WarmCodeCoverageCacheCommand implements Command { - private readonly Configuration $configuration; + private Configuration $configuration; - private readonly CodeCoverageFilterRegistry $codeCoverageFilterRegistry; + private CodeCoverageFilterRegistry $codeCoverageFilterRegistry; public function __construct(Configuration $configuration, CodeCoverageFilterRegistry $codeCoverageFilterRegistry) { @@ -76,16 +78,16 @@ final class WarmCodeCoverageCacheCommand implements Command if (! $this->configuration->hasCoverageCacheDirectory()) { return Result::from( 'Cache for static analysis has not been configured'.PHP_EOL, - Result::FAILURE + Result::FAILURE, ); } - $this->codeCoverageFilterRegistry->init($this->configuration); + $this->codeCoverageFilterRegistry->init($this->configuration, true); if (! $this->codeCoverageFilterRegistry->configured()) { return Result::from( 'Filter for code coverage has not been configured'.PHP_EOL, - Result::FAILURE + Result::FAILURE, ); } @@ -96,7 +98,7 @@ final class WarmCodeCoverageCacheCommand implements Command $this->configuration->coverageCacheDirectory(), ! $this->configuration->disableCodeCoverageIgnore(), $this->configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage(), - $this->codeCoverageFilterRegistry->get() + $this->codeCoverageFilterRegistry->get(), ); return Result::from(); diff --git a/overrides/TextUI/Output/Default/ProgressPrinter/TestSkippedSubscriber.php b/overrides/TextUI/Output/Default/ProgressPrinter/TestSkippedSubscriber.php index 80de0225..57c194a9 100644 --- a/overrides/TextUI/Output/Default/ProgressPrinter/TestSkippedSubscriber.php +++ b/overrides/TextUI/Output/Default/ProgressPrinter/TestSkippedSubscriber.php @@ -43,7 +43,7 @@ declare(strict_types=1); * file that was distributed with this source code. */ -namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; +namespace Pest\Logging\TeamCity\Subscriber; use PHPUnit\Event\Test\Skipped; use PHPUnit\Event\Test\SkippedSubscriber; @@ -51,21 +51,16 @@ use ReflectionClass; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit - * - * This file is overridden to allow Pest Parallel to show todo items in the progress output. */ final class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber { - /** - * Notifies the printer that a test was skipped. - */ public function notify(Skipped $event): void { if (str_contains($event->message(), '__TODO__')) { $this->printTodoItem(); } - $this->printer()->testSkipped(); + $this->logger()->testSkipped($event); } /** diff --git a/overrides/TextUI/TestSuiteFilterProcessor.php b/overrides/TextUI/TestSuiteFilterProcessor.php index f4473289..0ad8f356 100644 --- a/overrides/TextUI/TestSuiteFilterProcessor.php +++ b/overrides/TextUI/TestSuiteFilterProcessor.php @@ -57,7 +57,7 @@ use function array_map; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ -final class TestSuiteFilterProcessor +final readonly class TestSuiteFilterProcessor { private Factory $filterFactory; @@ -75,6 +75,7 @@ final class TestSuiteFilterProcessor if (! $configuration->hasFilter() && ! $configuration->hasGroups() && ! $configuration->hasExcludeGroups() && + ! $configuration->hasExcludeFilter() && ! $configuration->hasTestsCovering() && ! $configuration->hasTestsUsing() && ! Only::isEnabled() @@ -84,7 +85,7 @@ final class TestSuiteFilterProcessor if ($configuration->hasExcludeGroups()) { $this->filterFactory->addExcludeGroupFilter( - $configuration->excludeGroups() + $configuration->excludeGroups(), ); } @@ -92,7 +93,7 @@ final class TestSuiteFilterProcessor $this->filterFactory->addIncludeGroupFilter(['__pest_only']); } elseif ($configuration->hasGroups()) { $this->filterFactory->addIncludeGroupFilter( - $configuration->groups() + $configuration->groups(), ); } @@ -100,8 +101,8 @@ final class TestSuiteFilterProcessor $this->filterFactory->addIncludeGroupFilter( array_map( static fn (string $name): string => '__phpunit_covers_'.$name, - $configuration->testsCovering() - ) + $configuration->testsCovering(), + ), ); } @@ -109,21 +110,27 @@ final class TestSuiteFilterProcessor $this->filterFactory->addIncludeGroupFilter( array_map( static fn (string $name): string => '__phpunit_uses_'.$name, - $configuration->testsUsing() - ) + $configuration->testsUsing(), + ), + ); + } + + if ($configuration->hasExcludeFilter()) { + $this->filterFactory->addExcludeNameFilter( + $configuration->excludeFilter(), ); } if ($configuration->hasFilter()) { - $this->filterFactory->addNameFilter( - $configuration->filter() + $this->filterFactory->addIncludeNameFilter( + $configuration->filter(), ); } $suite->injectFilter($this->filterFactory); Event\Facade::emitter()->testSuiteFiltered( - Event\TestSuite\TestSuiteBuilder::from($suite) + Event\TestSuite\TestSuiteBuilder::from($suite), ); } }