Skip to content

Commit bea3903

Browse files
committed
Filters: add tests for GitModified and GitStaged filters
This is an initial set of tests for the `GitModified` and `GitStaged` filters. The tests are largely the same for both filters as the logic under test is also largely the same. Still, having separate test classes will allow for differentiating the tests if the logic in the filters themselves would start to diverge over time or if the output of the individual git commands would give reason to add extra tests. Notes: * To allow for mocking the output of the "git modified"/"git staged" commands, the handling of the function call to `exec` has been moved to a separate method in both the `GitModified`, as well as the `GitStaged` class. * This commit adds three new helper methods to the `AbstractFilterTestCase`: - `getMockedClass()` to handle creating a mock object of the filter under test in a PHPUnit cross-version compatible manner. - `getBaseDir()` to get the project root directory for use as the `$basedir` for the filters. - `getFakeFileList()` to get, as the name says, a fake file list for use in the tests, which contains a range of different file/directory situations which filter may need to take into account. Note: `.` and `..` are not included as the `PHP_CodeSniffer\Files\FileList` (which is basically what we're faking here) does not include those either, so that would create unrealistic test scenarios. Also note that, aside from some non-existent files added to the list for testing purposes, the files in this list _do_ actually need to exist for the tests to be valid.
1 parent d9b6f3c commit bea3903

File tree

5 files changed

+692
-5
lines changed

5 files changed

+692
-5
lines changed

src/Filters/GitModified.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ protected function getWhitelist()
3737
$modified = [];
3838

3939
$cmd = 'git ls-files -o -m --exclude-standard -- '.escapeshellarg($this->basedir);
40-
$output = [];
41-
exec($cmd, $output);
40+
$output = $this->exec($cmd);
4241

4342
$basedir = $this->basedir;
4443
if (is_dir($basedir) === false) {
@@ -63,4 +62,27 @@ protected function getWhitelist()
6362
}//end getWhitelist()
6463

6564

65+
/**
66+
* Execute an external command.
67+
*
68+
* {@internal This method is only needed to allow for mocking the return value
69+
* to test the class logic.}
70+
*
71+
* @param string $cmd Command.
72+
*
73+
* @return array
74+
*/
75+
protected function exec($cmd)
76+
{
77+
$output = [];
78+
$lastLine = exec($cmd, $output);
79+
if ($lastLine === false) {
80+
return [];
81+
}
82+
83+
return $output;
84+
85+
}//end exec()
86+
87+
6688
}//end class

src/Filters/GitStaged.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ protected function getWhitelist()
3939
$modified = [];
4040

4141
$cmd = 'git diff --cached --name-only -- '.escapeshellarg($this->basedir);
42-
$output = [];
43-
exec($cmd, $output);
42+
$output = $this->exec($cmd);
4443

4544
$basedir = $this->basedir;
4645
if (is_dir($basedir) === false) {
@@ -65,4 +64,27 @@ protected function getWhitelist()
6564
}//end getWhitelist()
6665

6766

67+
/**
68+
* Execute an external command.
69+
*
70+
* {@internal This method is only needed to allow for mocking the return value
71+
* to test the class logic.}
72+
*
73+
* @param string $cmd Command.
74+
*
75+
* @return array
76+
*/
77+
protected function exec($cmd)
78+
{
79+
$output = [];
80+
$lastLine = exec($cmd, $output);
81+
if ($lastLine === false) {
82+
return [];
83+
}
84+
85+
return $output;
86+
87+
}//end exec()
88+
89+
6890
}//end class

tests/Core/Filters/AbstractFilterTestCase.php

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,56 @@ abstract class AbstractFilterTestCase extends TestCase
4545
*/
4646
public static function initializeConfigAndRuleset()
4747
{
48-
self::$config = new Config(['--standard=PSR1', '--report-width=80']);
48+
self::$config = new Config(['--standard=PSR1', '--extensions=php,inc/php,js,css', '--report-width=80']);
4949
self::$ruleset = new Ruleset(self::$config);
5050

5151
}//end initializeConfigAndRuleset()
5252

5353

54+
/**
55+
* Helper method to retrieve a mock object for a Filter class.
56+
*
57+
* The `setMethods()` method was silently deprecated in PHPUnit 9 and removed in PHPUnit 10.
58+
*
59+
* Note: direct access to the `getMockBuilder()` method is soft deprecated as of PHPUnit 10,
60+
* and expected to be hard deprecated in PHPUnit 11 and removed in PHPUnit 12.
61+
* Dealing with that is something for a later iteration of the test suite.
62+
*
63+
* @param string $className Fully qualified name of the class under test.
64+
* @param array<mixed> $constructorArgs Optional. Array of parameters to pass to the class constructor.
65+
* @param array<string>|null $methodsToMock Optional. The methods to mock in the class under test.
66+
* Needed for PHPUnit cross-version support as PHPUnit 4.x does
67+
* not have a `setMethodsExcept()` method yet.
68+
* If not passed, no methods will be replaced.
69+
*
70+
* @return \PHPUnit\Framework\MockObject\MockObject
71+
*/
72+
protected function getMockedClass($className, array $constructorArgs=[], $methodsToMock=null)
73+
{
74+
$mockedObj = $this->getMockBuilder($className);
75+
76+
if (\method_exists($mockedObj, 'onlyMethods') === true) {
77+
// PHPUnit 8+.
78+
if (is_array($methodsToMock) === true) {
79+
return $mockedObj
80+
->setConstructorArgs($constructorArgs)
81+
->onlyMethods($methodsToMock)
82+
->getMock();
83+
}
84+
85+
return $mockedObj->getMock()
86+
->setConstructorArgs($constructorArgs);
87+
}
88+
89+
// PHPUnit < 8.
90+
return $mockedObj
91+
->setConstructorArgs($constructorArgs)
92+
->setMethods($methodsToMock)
93+
->getMock();
94+
95+
}//end getMockedClass()
96+
97+
5498
/**
5599
* Retrieve an array of files which were accepted by a filter.
56100
*
@@ -71,6 +115,85 @@ protected function getFilteredResultsAsArray(Filter $filter)
71115
}//end getFilteredResultsAsArray()
72116

73117

118+
/**
119+
* Retrieve the basedir to use for tests using the `getFakeFileList()` method.
120+
*
121+
* @return string
122+
*/
123+
protected static function getBaseDir()
124+
{
125+
return dirname(dirname(dirname(__DIR__)));
126+
127+
}//end getBaseDir()
128+
129+
130+
/**
131+
* Retrieve a file list containing a range of paths for testing purposes.
132+
*
133+
* This list **must** contain files which exist in this project (well, except for some which don't exist
134+
* purely for testing purposes), as `realpath()` is used in the logic under test and `realpath()` will
135+
* return `false` for any non-existent files, which will automatically filter them out before
136+
* we get to the code under test.
137+
*
138+
* Note this list does not include `.` and `..` as \PHP_CodeSniffer\Files\FileList uses `SKIP_DOTS`.
139+
*
140+
* @return array<string>
141+
*/
142+
protected static function getFakeFileList()
143+
{
144+
$basedir = self::getBaseDir();
145+
return [
146+
$basedir.'/.gitignore',
147+
$basedir.'/.yamllint.yml',
148+
$basedir.'/phpcs.xml',
149+
$basedir.'/phpcs.xml.dist',
150+
$basedir.'/autoload.php',
151+
$basedir.'/bin',
152+
$basedir.'/bin/phpcs',
153+
$basedir.'/bin/phpcs.bat',
154+
$basedir.'/scripts',
155+
$basedir.'/scripts/build-phar.php',
156+
$basedir.'/src',
157+
$basedir.'/src/WillNotExist.php',
158+
$basedir.'/src/WillNotExist.bak',
159+
$basedir.'/src/WillNotExist.orig',
160+
$basedir.'/src/Ruleset.php',
161+
$basedir.'/src/Generators',
162+
$basedir.'/src/Generators/Markdown.php',
163+
$basedir.'/src/Standards',
164+
$basedir.'/src/Standards/Generic',
165+
$basedir.'/src/Standards/Generic/Docs',
166+
$basedir.'/src/Standards/Generic/Docs/Classes',
167+
$basedir.'/src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml',
168+
$basedir.'/src/Standards/Generic/Sniffs',
169+
$basedir.'/src/Standards/Generic/Sniffs/Classes',
170+
$basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php',
171+
$basedir.'/src/Standards/Generic/Tests',
172+
$basedir.'/src/Standards/Generic/Tests/Classes',
173+
$basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.1.inc',
174+
// Will rarely exist when running the tests.
175+
$basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.1.inc.bak',
176+
$basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.2.inc',
177+
$basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.php',
178+
$basedir.'/src/Standards/Squiz',
179+
$basedir.'/src/Standards/Squiz/Docs',
180+
$basedir.'/src/Standards/Squiz/Docs/WhiteSpace',
181+
$basedir.'/src/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml',
182+
$basedir.'/src/Standards/Squiz/Sniffs',
183+
$basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace',
184+
$basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php',
185+
$basedir.'/src/Standards/Squiz/Tests',
186+
$basedir.'/src/Standards/Squiz/Tests/WhiteSpace',
187+
$basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc',
188+
$basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed',
189+
$basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js',
190+
$basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed',
191+
$basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php',
192+
];
193+
194+
}//end getFakeFileList()
195+
196+
74197
/**
75198
* Translate Linux paths to Windows paths, when necessary.
76199
*

0 commit comments

Comments
 (0)