feat: adjust overrides

This commit is contained in:
Nuno Maduro
2024-01-05 14:37:13 +00:00
parent f69a3cf832
commit 727a427837
6 changed files with 112 additions and 134 deletions

View File

@ -1,5 +1,37 @@
<?php <?php
/*
* BSD 3-Clause License
*
* Copyright (c) 2001-2023, Sebastian Bergmann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
declare(strict_types=1); declare(strict_types=1);
/* /*
@ -22,7 +54,7 @@ use PHPUnit\Util\ThrowableToStringMapper;
/** /**
* @internal This class is not covered by the backward compatibility promise for PHPUnit * @internal This class is not covered by the backward compatibility promise for PHPUnit
*/ */
final class ThrowableBuilder final readonly class ThrowableBuilder
{ {
/** /**
* @throws Exception * @throws Exception

View File

@ -32,11 +32,19 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Runner\Filter; namespace PHPUnit\Runner\Filter;
use Exception;
use Pest\Contracts\HasPrintableTestCaseName;
use PHPUnit\Framework\SelfDescribing;
use PHPUnit\Framework\Test; use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite; use PHPUnit\Framework\TestSuite;
@ -44,30 +52,41 @@ use RecursiveFilterIterator;
use RecursiveIterator; use RecursiveIterator;
use function end; use function end;
use function implode;
use function preg_match; use function preg_match;
use function sprintf;
use function str_replace;
/** /**
* @internal This class is not covered by the backward compatibility promise for PHPUnit * @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; /**
* @psalm-var non-empty-string
private ?int $filterMin = null; */
private readonly string $regularExpression;
private ?int $filterMax = null;
/** /**
* @throws Exception * @psalm-var ?int
*/
private readonly ?int $dataSetMinimum;
/**
* @psalm-var ?int
*/
private readonly ?int $dataSetMaximum;
/**
* @psalm-param RecursiveIterator<int, Test> $iterator
* @psalm-param non-empty-string $filter
*/ */
public function __construct(RecursiveIterator $iterator, string $filter) public function __construct(RecursiveIterator $iterator, string $filter)
{ {
parent::__construct($iterator); 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 public function accept(): bool
@ -78,95 +97,26 @@ final class NameFilterIterator extends RecursiveFilterIterator
return true; return true;
} }
$tmp = $this->describe($test); if (! $test instanceof TestCase) {
return false;
if ($tmp[0] !== '') {
$name = implode('::', $tmp);
} else {
$name = $tmp[1];
} }
$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); $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 abstract protected function prepareFilter(string $filter): array;
{
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];
}
} }

View File

@ -81,11 +81,6 @@ final class DefaultResultCache implements ResultCache
*/ */
private array $defects = []; private array $defects = [];
/**
* @psalm-var array<string, TestStatus>
*/
private array $currentDefects = [];
/** /**
* @psalm-var array<string, float> * @psalm-var array<string, float>
*/ */
@ -102,10 +97,11 @@ final class DefaultResultCache implements ResultCache
public function setStatus(string $id, TestStatus $status): void public function setStatus(string $id, TestStatus $status): void
{ {
if ($status->isFailure() || $status->isError()) { if ($status->isSuccess()) {
$this->currentDefects[$id] = $status; return;
$this->defects[$id] = $status;
} }
$this->defects[$id] = $status;
} }
public function status(string $id): TestStatus public function status(string $id): TestStatus
@ -115,10 +111,6 @@ final class DefaultResultCache implements ResultCache
public function setTime(string $id, float $time): void public function setTime(string $id, float $time): void
{ {
if (! isset($this->currentDefects[$id])) {
unset($this->defects[$id]);
}
$this->times[$id] = $time; $this->times[$id] = $time;
} }
@ -135,7 +127,7 @@ final class DefaultResultCache implements ResultCache
$data = json_decode( $data = json_decode(
file_get_contents($this->cacheFilename), file_get_contents($this->cacheFilename),
true true,
); );
if ($data === null) { if ($data === null) {
@ -183,7 +175,7 @@ final class DefaultResultCache implements ResultCache
file_put_contents( file_put_contents(
$this->cacheFilename, $this->cacheFilename,
json_encode($data), json_encode($data),
LOCK_EX LOCK_EX,
); );
} }

View File

@ -45,6 +45,8 @@ declare(strict_types=1);
namespace PHPUnit\TextUI\Command; namespace PHPUnit\TextUI\Command;
use const PHP_EOL;
use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry;
use PHPUnit\TextUI\Configuration\Configuration; use PHPUnit\TextUI\Configuration\Configuration;
use PHPUnit\TextUI\Configuration\NoCoverageCacheDirectoryException; 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 * @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) public function __construct(Configuration $configuration, CodeCoverageFilterRegistry $codeCoverageFilterRegistry)
{ {
@ -76,16 +78,16 @@ final class WarmCodeCoverageCacheCommand implements Command
if (! $this->configuration->hasCoverageCacheDirectory()) { if (! $this->configuration->hasCoverageCacheDirectory()) {
return Result::from( return Result::from(
'Cache for static analysis has not been configured'.PHP_EOL, '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()) { if (! $this->codeCoverageFilterRegistry->configured()) {
return Result::from( return Result::from(
'Filter for code coverage has not been configured'.PHP_EOL, '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->coverageCacheDirectory(),
! $this->configuration->disableCodeCoverageIgnore(), ! $this->configuration->disableCodeCoverageIgnore(),
$this->configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage(), $this->configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage(),
$this->codeCoverageFilterRegistry->get() $this->codeCoverageFilterRegistry->get(),
); );
return Result::from(); return Result::from();

View File

@ -43,7 +43,7 @@ declare(strict_types=1);
* file that was distributed with this source code. * 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\Skipped;
use PHPUnit\Event\Test\SkippedSubscriber; use PHPUnit\Event\Test\SkippedSubscriber;
@ -51,21 +51,16 @@ use ReflectionClass;
/** /**
* @internal This class is not covered by the backward compatibility promise for PHPUnit * @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 final class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber
{ {
/**
* Notifies the printer that a test was skipped.
*/
public function notify(Skipped $event): void public function notify(Skipped $event): void
{ {
if (str_contains($event->message(), '__TODO__')) { if (str_contains($event->message(), '__TODO__')) {
$this->printTodoItem(); $this->printTodoItem();
} }
$this->printer()->testSkipped(); $this->logger()->testSkipped($event);
} }
/** /**

View File

@ -57,7 +57,7 @@ use function array_map;
/** /**
* @internal This class is not covered by the backward compatibility promise for PHPUnit * @internal This class is not covered by the backward compatibility promise for PHPUnit
*/ */
final class TestSuiteFilterProcessor final readonly class TestSuiteFilterProcessor
{ {
private Factory $filterFactory; private Factory $filterFactory;
@ -75,6 +75,7 @@ final class TestSuiteFilterProcessor
if (! $configuration->hasFilter() && if (! $configuration->hasFilter() &&
! $configuration->hasGroups() && ! $configuration->hasGroups() &&
! $configuration->hasExcludeGroups() && ! $configuration->hasExcludeGroups() &&
! $configuration->hasExcludeFilter() &&
! $configuration->hasTestsCovering() && ! $configuration->hasTestsCovering() &&
! $configuration->hasTestsUsing() && ! $configuration->hasTestsUsing() &&
! Only::isEnabled() ! Only::isEnabled()
@ -84,7 +85,7 @@ final class TestSuiteFilterProcessor
if ($configuration->hasExcludeGroups()) { if ($configuration->hasExcludeGroups()) {
$this->filterFactory->addExcludeGroupFilter( $this->filterFactory->addExcludeGroupFilter(
$configuration->excludeGroups() $configuration->excludeGroups(),
); );
} }
@ -92,7 +93,7 @@ final class TestSuiteFilterProcessor
$this->filterFactory->addIncludeGroupFilter(['__pest_only']); $this->filterFactory->addIncludeGroupFilter(['__pest_only']);
} elseif ($configuration->hasGroups()) { } elseif ($configuration->hasGroups()) {
$this->filterFactory->addIncludeGroupFilter( $this->filterFactory->addIncludeGroupFilter(
$configuration->groups() $configuration->groups(),
); );
} }
@ -100,8 +101,8 @@ final class TestSuiteFilterProcessor
$this->filterFactory->addIncludeGroupFilter( $this->filterFactory->addIncludeGroupFilter(
array_map( array_map(
static fn (string $name): string => '__phpunit_covers_'.$name, static fn (string $name): string => '__phpunit_covers_'.$name,
$configuration->testsCovering() $configuration->testsCovering(),
) ),
); );
} }
@ -109,21 +110,27 @@ final class TestSuiteFilterProcessor
$this->filterFactory->addIncludeGroupFilter( $this->filterFactory->addIncludeGroupFilter(
array_map( array_map(
static fn (string $name): string => '__phpunit_uses_'.$name, static fn (string $name): string => '__phpunit_uses_'.$name,
$configuration->testsUsing() $configuration->testsUsing(),
) ),
);
}
if ($configuration->hasExcludeFilter()) {
$this->filterFactory->addExcludeNameFilter(
$configuration->excludeFilter(),
); );
} }
if ($configuration->hasFilter()) { if ($configuration->hasFilter()) {
$this->filterFactory->addNameFilter( $this->filterFactory->addIncludeNameFilter(
$configuration->filter() $configuration->filter(),
); );
} }
$suite->injectFilter($this->filterFactory); $suite->injectFilter($this->filterFactory);
Event\Facade::emitter()->testSuiteFiltered( Event\Facade::emitter()->testSuiteFiltered(
Event\TestSuite\TestSuiteBuilder::from($suite) Event\TestSuite\TestSuiteBuilder::from($suite),
); );
} }
} }