Skip to content

Commit 285e655

Browse files
committed
Merge branch 'master' into 4.x
2 parents eaab59a + b1bf062 commit 285e655

File tree

7 files changed

+353
-1
lines changed

7 files changed

+353
-1
lines changed

src/Files/FileList.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,14 @@ public function __construct(Config $config, Ruleset $ruleset)
9393

9494
foreach ($iterator as $file) {
9595
$this->files[$file->getPathname()] = null;
96-
$this->numFiles++;
9796
}
9897
} else {
9998
$this->addFile($path);
10099
}//end if
101100
}//end foreach
102101

103102
reset($this->files);
103+
$this->numFiles = count($this->files);
104104

105105
}//end __construct()
106106

@@ -133,6 +133,11 @@ public function addFile($path, $file=null)
133133
$iterator = new RecursiveIteratorIterator($filter);
134134

135135
foreach ($iterator as $path) {
136+
if (array_key_exists($path, $this->files) === true) {
137+
// The path has already been added.
138+
continue;
139+
}
140+
136141
$this->files[$path] = $file;
137142
$this->numFiles++;
138143
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
/**
3+
* Abstract testcase class for testing FileList methods.
4+
*
5+
* @copyright 2025 PHPCSStandards Contributors
6+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
7+
*/
8+
9+
namespace PHP_CodeSniffer\Tests\Core\Files\FileList;
10+
11+
use PHP_CodeSniffer\Ruleset;
12+
use PHP_CodeSniffer\Tests\ConfigDouble;
13+
use PHPUnit\Framework\TestCase;
14+
15+
/**
16+
* Base functionality and utilities for testing FileList methods.
17+
*/
18+
abstract class AbstractFileListTestCase extends TestCase
19+
{
20+
21+
/**
22+
* The Config object.
23+
*
24+
* @var \PHP_CodeSniffer\Config
25+
*/
26+
protected static $config;
27+
28+
/**
29+
* The Ruleset object.
30+
*
31+
* @var \PHP_CodeSniffer\Ruleset
32+
*/
33+
protected static $ruleset;
34+
35+
36+
/**
37+
* Initialize the config and ruleset objects only once.
38+
*
39+
* @return void
40+
*/
41+
public static function setUpBeforeClass(): void
42+
{
43+
// Wrapped in an `isset()` as the properties may have been set already (via a call to this method from a dataprovider).
44+
if (isset(self::$ruleset) === false) {
45+
self::$config = new ConfigDouble();
46+
self::$config->filter = __DIR__.'/FilterDouble.php';
47+
self::$ruleset = new Ruleset(self::$config);
48+
}
49+
50+
}//end setUpBeforeClass()
51+
52+
53+
}//end class
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
/**
3+
* Tests for the \PHP_CodeSniffer\Files\FileList::addFile method.
4+
*
5+
* @copyright 2025 PHPCSStandards Contributors
6+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
7+
*/
8+
9+
namespace PHP_CodeSniffer\Tests\Core\Files\FileList;
10+
11+
use PHP_CodeSniffer\Files\File;
12+
use PHP_CodeSniffer\Files\FileList;
13+
14+
/**
15+
* Tests for the \PHP_CodeSniffer\Files\FileList::addFile method.
16+
*
17+
* @covers \PHP_CodeSniffer\Files\FileList::addFile
18+
*/
19+
final class AddFileTest extends AbstractFileListTestCase
20+
{
21+
22+
/**
23+
* The FileList object.
24+
*
25+
* @var \PHP_CodeSniffer\Files\FileList
26+
*/
27+
private $fileList;
28+
29+
30+
/**
31+
* Initialize the FileList object.
32+
*
33+
* @return void
34+
*/
35+
protected function setUp(): void
36+
{
37+
self::$config->files = [];
38+
$this->fileList = new FileList(self::$config, self::$ruleset);
39+
40+
}//end setUp()
41+
42+
43+
/**
44+
* Test adding a file to the list.
45+
*
46+
* @param string $fileName The name of the file to add.
47+
* @param object|null $fileObject An optional file object to add instead of creating a new one.
48+
*
49+
* @dataProvider dataAddFile
50+
*
51+
* @return void
52+
*/
53+
public function testAddFile($fileName, $fileObject=null)
54+
{
55+
$this->assertCount(0, $this->fileList);
56+
57+
$this->fileList->addFile($fileName, $fileObject);
58+
59+
$fileListArray = iterator_to_array($this->fileList);
60+
61+
$this->assertCount(1, $this->fileList, 'File count mismatch');
62+
$this->assertArrayHasKey($fileName, $fileListArray, 'File not found in list');
63+
64+
if (isset($fileObject) === true) {
65+
$this->assertSame($fileObject, $fileListArray[$fileName], 'File object mismatch');
66+
} else {
67+
$this->assertInstanceOf(
68+
File::class,
69+
$fileListArray[$fileName],
70+
'File object not found in list'
71+
);
72+
}
73+
74+
}//end testAddFile()
75+
76+
77+
/**
78+
* Data provider for testAddFile.
79+
*
80+
* @return array<string, array<string, string|object>>
81+
*/
82+
public static function dataAddFile()
83+
{
84+
self::setUpBeforeClass();
85+
86+
return [
87+
'Regular file' => [
88+
'fileName' => 'test1.php',
89+
],
90+
'STDIN' => [
91+
'fileName' => 'STDIN',
92+
],
93+
'Regular file with file object' => [
94+
'fileName' => 'test1.php',
95+
'fileObject' => new File('test1.php', self::$ruleset, self::$config),
96+
],
97+
];
98+
99+
}//end dataAddFile()
100+
101+
102+
/**
103+
* Test that it is not possible to add the same file twice.
104+
*
105+
* @return void
106+
*/
107+
public function testAddFileShouldNotAddTheSameFileTwice()
108+
{
109+
$file1 = 'test1.php';
110+
$file2 = 'test2.php';
111+
$expectedFiles = [
112+
$file1,
113+
$file2,
114+
];
115+
116+
// Add $file1 once.
117+
$this->fileList->addFile($file1);
118+
$this->assertCount(1, $this->fileList);
119+
$this->assertSame([$file1], array_keys(iterator_to_array($this->fileList)));
120+
121+
// Try to add $file1 again. Should be ignored.
122+
$this->fileList->addFile($file1);
123+
$this->assertCount(1, $this->fileList);
124+
$this->assertSame([$file1], array_keys(iterator_to_array($this->fileList)));
125+
126+
// Add $file2. Should be added.
127+
$this->fileList->addFile($file2);
128+
$this->assertCount(2, $this->fileList);
129+
$this->assertSame($expectedFiles, array_keys(iterator_to_array($this->fileList)));
130+
131+
}//end testAddFileShouldNotAddTheSameFileTwice()
132+
133+
134+
}//end class
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
/**
3+
* Tests for the \PHP_CodeSniffer\Files\FileList::__construct method.
4+
*
5+
* @copyright 2025 PHPCSStandards Contributors
6+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
7+
*/
8+
9+
namespace PHP_CodeSniffer\Tests\Core\Files\FileList;
10+
11+
use PHP_CodeSniffer\Files\File;
12+
use PHP_CodeSniffer\Files\FileList;
13+
14+
/**
15+
* Tests for the \PHP_CodeSniffer\Files\FileList::__construct method.
16+
*
17+
* @covers \PHP_CodeSniffer\Files\FileList::__construct
18+
*/
19+
final class ConstructTest extends AbstractFileListTestCase
20+
{
21+
22+
23+
/**
24+
* Test the __construct() method.
25+
*
26+
* @param array<string> $files List of file paths in the Config class.
27+
* @param array<string> $expectedFiles List of expected file paths in the FileList.
28+
*
29+
* @dataProvider dataConstruct
30+
*
31+
* @return void
32+
*/
33+
public function testConstruct($files, $expectedFiles)
34+
{
35+
self::$config->files = $files;
36+
37+
$fileList = new FileList(self::$config, self::$ruleset);
38+
39+
$this->assertSame(self::$config, $fileList->config, 'Config object mismatch');
40+
$this->assertSame(self::$ruleset, $fileList->ruleset, 'Ruleset object mismatch');
41+
42+
$this->assertSameSize($expectedFiles, $fileList, 'File count mismatch');
43+
44+
$i = 0;
45+
46+
// Sort the values to make the tests stable as different OSes will read directories
47+
// in a different order and the order is not relevant for these tests. Just the values.
48+
$fileListArray = iterator_to_array($fileList);
49+
ksort($fileListArray);
50+
51+
foreach ($fileListArray as $filePath => $fileObject) {
52+
$this->assertSame(
53+
$expectedFiles[$i],
54+
$filePath,
55+
sprintf('File path mismatch: expected "%s", got "%s"', $expectedFiles[$i], $filePath)
56+
);
57+
$this->assertInstanceOf(
58+
File::class,
59+
$fileObject,
60+
sprintf('File object for "%s" is not an instance of PHP_CodeSniffer\Files\File', $filePath)
61+
);
62+
$i++;
63+
}
64+
65+
}//end testConstruct()
66+
67+
68+
/**
69+
* Data provider for testConstruct.
70+
*
71+
* @return array<string, array<string, array<string>>>
72+
*/
73+
public static function dataConstruct()
74+
{
75+
$fixturesDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR;
76+
77+
return [
78+
'No files' => [
79+
'files' => [],
80+
'expectedFiles' => [],
81+
],
82+
'Two files' => [
83+
'files' => [
84+
'file1.php',
85+
'file2.php',
86+
],
87+
'expectedFiles' => [
88+
'file1.php',
89+
'file2.php',
90+
],
91+
],
92+
'A directory' => [
93+
'files' => [$fixturesDir],
94+
'expectedFiles' => [
95+
$fixturesDir.'file1.php',
96+
$fixturesDir.'file2.php',
97+
],
98+
],
99+
'Same file twice' => [
100+
'files' => [
101+
'file1.php',
102+
'file1.php',
103+
],
104+
'expectedFiles' => [
105+
'file1.php',
106+
],
107+
],
108+
'File and then directory containing that file' => [
109+
'files' => [
110+
$fixturesDir.'file1.php',
111+
$fixturesDir,
112+
],
113+
'expectedFiles' => [
114+
$fixturesDir.'file1.php',
115+
$fixturesDir.'file2.php',
116+
],
117+
],
118+
];
119+
120+
}//end dataConstruct()
121+
122+
123+
}//end class
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
/**
3+
* Double of the filter class that will accept every file. Used in the FileList tests.
4+
*
5+
* @copyright 2025 PHPCSStandards Contributors
6+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
7+
*/
8+
9+
namespace PHP_CodeSniffer\Tests\Core\Files\FileList;
10+
11+
use PHP_CodeSniffer\Filters\Filter;
12+
use ReturnTypeWillChange;
13+
14+
final class FilterDouble extends Filter
15+
{
16+
17+
18+
/**
19+
* Accepts every file.
20+
*
21+
* @return true
22+
*/
23+
#[ReturnTypeWillChange]
24+
public function accept()
25+
{
26+
return true;
27+
28+
}//end accept()
29+
30+
31+
}//end class
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
3+
// Empty file for testing purposes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
3+
// Empty file for testing purposes.

0 commit comments

Comments
 (0)