Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

--exclude-filter CLI option for excluding tests from execution #5629

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 18 additions & 5 deletions .psalm/baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -621,17 +621,26 @@
<code><![CDATA[$this->groupTests]]></code>
</PropertyTypeCoercion>
</file>
<file src="src/Runner/Filter/NameFilterIterator.php">
<file src="src/Runner/Filter/IncludeNameFilterIterator.php">
<ArgumentTypeCoercion>
<code>$filter</code>
<code><![CDATA[$this->filter]]></code>
</ArgumentTypeCoercion>
</file>
<file src="src/Runner/Filter/ExcludeNameFilterIterator.php">
<ArgumentTypeCoercion>
<code>$filter</code>
</ArgumentTypeCoercion>
</file>
<file src="src/Runner/Filter/NameFilterIterator.php">
<ArgumentTypeCoercion>
<code><![CDATA[$this->filter]]></code>
</ArgumentTypeCoercion>
<PropertyNotSetInConstructor>
<code>$filter</code>
</PropertyNotSetInConstructor>
<MissingTemplateParam>
<code>NameFilterIterator</code>
</MissingTemplateParam>
<PossiblyNullArgument>
<code><![CDATA[$this->filter]]></code>
</PossiblyNullArgument>
</file>
<file src="src/Runner/Filter/TestIdFilterIterator.php">
<MissingTemplateParam>
Expand Down Expand Up @@ -671,6 +680,9 @@
</UnresolvableInclude>
</file>
<file src="src/Runner/TestSuiteSorter.php">
<MissingThrowsDocblock>
<code>$suite</code>
</MissingThrowsDocblock>
<ArgumentTypeCoercion>
<code>$tests</code>
<code><![CDATA[$this->randomize($suite->tests())]]></code>
Expand Down Expand Up @@ -951,6 +963,7 @@
<file src="src/TextUI/TestSuiteFilterProcessor.php">
<ArgumentTypeCoercion>
<code><![CDATA[$configuration->excludeGroups()]]></code>
<code><![CDATA[$configuration->excludeFilter()]]></code>
<code><![CDATA[$configuration->filter()]]></code>
<code><![CDATA[$configuration->groups()]]></code>
</ArgumentTypeCoercion>
Expand Down
3 changes: 3 additions & 0 deletions src/Event/Value/TestSuite/TestSuiteBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
final readonly class TestSuiteBuilder
{
/**
* @throws ReflectionException
* @throws RuntimeException
*/
public static function from(FrameworkTestSuite $testSuite): TestSuite
Expand Down Expand Up @@ -104,6 +105,8 @@ public static function from(FrameworkTestSuite $testSuite): TestSuite

/**
* @psalm-param list<Test> $tests
*
* @throws ReflectionException
*/
private static function process(FrameworkTestSuite $testSuite, &$tests): void
{
Expand Down
15 changes: 15 additions & 0 deletions src/Framework/TestSuite.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
use PHPUnit\Util\Reflection;
use PHPUnit\Util\Test as TestUtil;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException;
use Throwable;
Expand Down Expand Up @@ -261,6 +262,8 @@ public function addTestFiles(iterable $fileNames): void

/**
* Counts the number of test cases that will be run by this test.
*
* @throws ReflectionException
*/
public function count(): int
{
Expand Down Expand Up @@ -310,6 +313,7 @@ public function groupDetails(): array
* @throws Event\RuntimeException
* @throws Exception
* @throws NoPreviousThrowableException
* @throws ReflectionException
* @throws UnintentionallyCoveredCodeException
*/
public function run(): void
Expand Down Expand Up @@ -374,6 +378,8 @@ public function markTestSuiteSkipped(string $message = ''): never

/**
* Returns an iterator for this test suite.
*
* @throws ReflectionException
*/
public function getIterator(): Iterator
{
Expand All @@ -386,6 +392,9 @@ public function getIterator(): Iterator
return $iterator;
}

/**
* @throws ReflectionException
*/
public function injectFilter(Factory $filter): void
{
$this->iteratorFilter = $filter;
Expand Down Expand Up @@ -530,6 +539,9 @@ private function containsOnlyVirtualGroups(array $groups): bool
return true;
}

/**
* @throws ReflectionException
*/
private function methodDoesNotExistOrIsDeclaredInTestCase(string $methodName): bool
{
$reflector = new ReflectionClass($this->name);
Expand Down Expand Up @@ -639,6 +651,9 @@ private function invokeMethodsBeforeFirstTest(Event\Emitter $emitter, Event\Test
return true;
}

/**
* @throws ReflectionException
*/
private function invokeMethodsAfterLastTest(Event\Emitter $emitter): void
{
if (!$this->isForTestClass()) {
Expand Down
37 changes: 37 additions & 0 deletions src/Runner/Filter/ExcludeNameFilterIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php 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;

use function preg_match;
use function sprintf;
use function str_replace;
use Exception;

class ExcludeNameFilterIterator extends NameFilterIterator
{
/**
* @throws Exception
*/
protected function setFilter(string $filter): void
{
if (@preg_match($filter, '') === false) {
$filter = sprintf(
'/^(?:(?!%s).)*/i',
str_replace(
'/',
'\\/',
$filter,
),
);
}

$this->filter = $filter;
}
}
16 changes: 15 additions & 1 deletion src/Runner/Filter/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Iterator;
use PHPUnit\Framework\TestSuite;
use ReflectionClass;
use ReflectionException;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
Expand Down Expand Up @@ -61,10 +62,23 @@ public function addIncludeGroupFilter(array $groups): void
public function addNameFilter(string $name): void
{
$this->filters[] = [
new ReflectionClass(NameFilterIterator::class), $name,
new ReflectionClass(IncludeNameFilterIterator::class), $name,
];
}

/**
* @psalm-param non-empty-string $name
*/
public function addExcludeNameFilter(string $name): void
{
$this->filters[] = [
new ReflectionClass(ExcludeNameFilterIterator::class), $name,
];
}

/**
* @throws ReflectionException
*/
public function factory(Iterator $iterator, TestSuite $suite): FilterIterator
{
foreach ($this->filters as $filter) {
Expand Down
65 changes: 65 additions & 0 deletions src/Runner/Filter/IncludeNameFilterIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php 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;

use function preg_match;
use function sprintf;
use function str_replace;

final class IncludeNameFilterIterator extends NameFilterIterator
{
protected 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 data set #(\d+)$',
$matches[1],
);

$this->filterMin = (int) $matches[2];
$this->filterMax = (int) $matches[3];
} else {
$filter = sprintf(
'%s.*with data set #%s$',
$matches[1],
$matches[2],
);
}
} // Handles:
// * testDetermineJsonError@JSON_ERROR_NONE
// * testDetermineJsonError@JSON.*
elseif (preg_match('/^(.*?)@(.+)$/', $filter, $matches)) {
$filter = sprintf(
'%s.*with data set "%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;
}
}