Skip to content

Commit

Permalink
Just like in php-code-coverage, we need to use php-file-iterator to q…
Browse files Browse the repository at this point in the history
…uery the filesystem for a list of files because globbing should be supported
  • Loading branch information
sebastianbergmann committed Apr 4, 2023
1 parent 1b61935 commit 87e6e5c
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 55 deletions.
8 changes: 8 additions & 0 deletions .psalm/baseline.xml
Expand Up @@ -650,6 +650,14 @@
<code>assert($xmlConfiguration instanceof LoadedFromFileConfiguration)</code>
</RedundantCondition>
</file>
<file src="src/TextUI/Configuration/SourceFilter.php">
<InvalidArgument>
<code>$files</code>
<code>$source</code>
<code>$source</code>
<code>$source</code>
</InvalidArgument>
</file>
<file src="src/TextUI/Configuration/TestSuiteBuilder.php">
<MissingThrowsDocblock>
<code>\PHPUnit\Event\TestSuite\TestSuiteBuilder::from($testSuite)</code>
Expand Down
91 changes: 60 additions & 31 deletions src/TextUI/Configuration/SourceFilter.php
Expand Up @@ -9,62 +9,91 @@
*/
namespace PHPUnit\TextUI\Configuration;

use function basename;
use function str_ends_with;
use function str_starts_with;
use function realpath;
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
use SplObjectStorage;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*
* @psalm-immutable
*/
final class SourceFilter
{
/**
* @psalm-var SplObjectStorage<Source, array<non-empty-string, true>>
*/
private static ?SplObjectStorage $files = null;

public function includes(Source $source, string $path): bool
{
if ($this->fileCollectionHas($source->excludeFiles(), $path)) {
return false;
$this->process($source);

return isset(self::$files[$source][$path]);
}

private function process(Source $source): void
{
if (self::$files === null) {
self::$files = new SplObjectStorage;
}

if ($this->fileCollectionHas($source->includeFiles(), $path)) {
return true;
if (isset(self::$files[$source])) {
return;
}

return $this->directoryMatches($source->includeDirectories(), $path) &&
!$this->directoryMatches($source->excludeDirectories(), $path);
}
$files = [];

private function directoryMatches(FilterDirectoryCollection $directories, string $path): bool
{
$filename = basename($path);
foreach ($source->includeDirectories() as $directory) {
foreach ((new FileIteratorFacade)->getFilesAsArray($directory->path(), $directory->suffix(), $directory->prefix()) as $file) {
$file = realpath($file);

foreach ($directories as $directory) {
if (!str_starts_with($path, $directory->path())) {
continue;
}
if (!$file) {
continue;
}

if (!empty($directory->prefix()) && !str_starts_with($filename, $directory->prefix())) {
continue;
$files[$file] = true;
}
}

foreach ($source->includeFiles() as $file) {
$file = realpath($file->path());

if (!empty($directory->suffix()) && !str_ends_with($filename, $directory->suffix())) {
if (!$file) {
continue;
}

return true;
$files[$file] = true;
}

return false;
}
foreach ($source->excludeDirectories() as $directory) {
foreach ((new FileIteratorFacade)->getFilesAsArray($directory->path(), $directory->suffix(), $directory->prefix()) as $file) {
$file = realpath($file);

private function fileCollectionHas(FileCollection $files, string $path): bool
{
foreach ($files as $file) {
if ($file->path() === $path) {
return true;
if (!$file) {
continue;
}

if (!isset($files[$file])) {
continue;
}

unset($files[$file]);
}
}

return false;
foreach ($source->excludeFiles() as $file) {
$file = realpath($file->path());

if (!$file) {
continue;
}

if (!isset($files[$file])) {
continue;
}

unset($files[$file]);
}

self::$files[$source] = $files;
}
}
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
73 changes: 49 additions & 24 deletions tests/unit/TextUI/SourceFilterTest.php
Expand Up @@ -9,6 +9,7 @@
*/
namespace PHPUnit\TextUI\Configuration;

use function realpath;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Small;
Expand All @@ -20,47 +21,71 @@ final class SourceFilterTest extends TestCase
{
public static function provider(): array
{
$fixtureDirectory = realpath(__DIR__ . '/../../_files/source-filter');

return [
'file included using file' => [
true,
'/path/to/source.php',
$fixtureDirectory . '/a/PrefixSuffix.php',
new Source(
FilterDirectoryCollection::fromArray([]),
FileCollection::fromArray(
[
new File('/path/to/source.php'),
new File($fixtureDirectory . '/a/PrefixSuffix.php'),
]
),
FilterDirectoryCollection::fromArray([]),
FileCollection::fromArray([]),
),
],
'file included using file, but also excluded using file' => [
'file included using file, but excluded using directory' => [
false,
$fixtureDirectory . '/a/PrefixSuffix.php',
new Source(
FilterDirectoryCollection::fromArray([]),
FileCollection::fromArray(
[
new File($fixtureDirectory . '/a/PrefixSuffix.php'),
]
),
FilterDirectoryCollection::fromArray(
[
new FilterDirectory(
$fixtureDirectory . '/a',
'',
'.php'
),
]
),
FileCollection::fromArray([]),
),
],
'file included using file, but excluded using file' => [
false,
'/path/to/source.php',
$fixtureDirectory . '/a/PrefixSuffix.php',
new Source(
FilterDirectoryCollection::fromArray([]),
FileCollection::fromArray(
[
new File('/path/to/source.php'),
new File($fixtureDirectory . '/a/PrefixSuffix.php'),
]
),
FilterDirectoryCollection::fromArray([]),
FileCollection::fromArray(
[
new File('/path/to/source.php'),
new File($fixtureDirectory . '/a/PrefixSuffix.php'),
]
),
),
],
'file included using directory' => [
true,
'/path/to/source.php',
$fixtureDirectory . '/a/PrefixSuffix.php',
new Source(
FilterDirectoryCollection::fromArray(
[
new FilterDirectory(
'/path',
$fixtureDirectory,
'',
'.php'
),
Expand All @@ -71,52 +96,52 @@ public static function provider(): array
FileCollection::fromArray([]),
),
],
'file included using directory, but excluded using directory' => [
'file included using directory, but excluded using file' => [
false,
'/path/to/source.php',
$fixtureDirectory . '/a/PrefixSuffix.php',
new Source(
FilterDirectoryCollection::fromArray(
[
new FilterDirectory(
'/path',
$fixtureDirectory,
'',
'.php'
),
]
),
FileCollection::fromArray([]),
FilterDirectoryCollection::fromArray(
FilterDirectoryCollection::fromArray([]),
FileCollection::fromArray(
[
new FilterDirectory(
'/path/to',
'',
'.php'
),
new File($fixtureDirectory . '/a/PrefixSuffix.php'),
]
),
FileCollection::fromArray([]),
),
],
'file included using directory, but excluded using file' => [
'file included using directory, but excluded using directory' => [
false,
'/path/to/source.php',
$fixtureDirectory . '/a/PrefixSuffix.php',
new Source(
FilterDirectoryCollection::fromArray(
[
new FilterDirectory(
'/path',
$fixtureDirectory,
'',
'.php'
),
]
),
FileCollection::fromArray([]),
FilterDirectoryCollection::fromArray([]),
FileCollection::fromArray(
FilterDirectoryCollection::fromArray(
[
new File('/path/to/source.php'),
new FilterDirectory(
$fixtureDirectory . '/a',
'',
'.php'
),
]
),
FileCollection::fromArray([]),
),
],
];
Expand Down

0 comments on commit 87e6e5c

Please sign in to comment.