Skip to content

Commit aab0862

Browse files
committed
Merge pull request #754 from PHPCSStandards/feature/ruleset-process-ruleset-add-more-tests
Ruleset::processRuleset(): add various tests for things not already covered
2 parents 32c5cd9 + a0ef032 commit aab0862

7 files changed

+321
-0
lines changed

tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="InvalidNoSniffsDir" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
</ruleset>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
5+
6+
<rule ref="TestStandard"/>
7+
8+
</ruleset>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<rule ref="PSR1">
5+
<exclude name="Generic"/>
6+
<exclude name="PSR1.Files"/>
7+
<exclude name="Squiz.Classes.ValidClassName"/>
8+
</rule>
9+
10+
</ruleset>
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/"/>
5+
6+
<rule ref="InvalidNoSniffsDir"/>
7+
8+
<!-- Prevent a "no sniff were registered" error. -->
9+
<rule ref="Generic.PHP.BacktickOperator"/>
10+
</ruleset>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<!-- Error handling: Ini missing "name" will be ignored. -->
5+
<ini value="2"/>
6+
7+
<!-- Error handling: Ini missing "value" will be set to true. -->
8+
<ini name="user_agent"/>
9+
10+
<!-- Include of error code after previous exclude of most of a sniff via another error code include. -->
11+
<rule ref="PEAR.Files.IncludingFile.BracketsNotRequired"/>
12+
<rule ref="PEAR.Files.IncludingFile.UseRequire"/>
13+
14+
<!-- Include single error code. -->
15+
<rule ref="Generic.PHP.RequireStrictTypes.MissingDeclaration"/>
16+
17+
<!-- Error handling: Rule without ref. -->
18+
<rule name="Generic.Metrics.CyclomaticComplexity"/>
19+
20+
<!-- Error handling: Exclude without name. -->
21+
<rule ref="Generic.PHP.BacktickOperator">
22+
<exclude ref="Generic.PHP.BacktickOperator.Found"/>
23+
</rule>
24+
25+
</ruleset>
+263
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
<?php
2+
/**
3+
* Test the Ruleset::processRuleset() method.
4+
*
5+
* @author Juliette Reinders Folmer <[email protected]>
6+
* @copyright 2024 PHPCSStandards and contributors
7+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8+
*/
9+
10+
namespace PHP_CodeSniffer\Tests\Core\Ruleset;
11+
12+
use PHP_CodeSniffer\Ruleset;
13+
use PHP_CodeSniffer\Tests\ConfigDouble;
14+
use PHPUnit\Framework\TestCase;
15+
16+
/**
17+
* Test various aspects of the Ruleset::processRuleset() method not covered via other tests.
18+
*
19+
* @covers \PHP_CodeSniffer\Ruleset::processRuleset
20+
*/
21+
final class ProcessRulesetTest extends TestCase
22+
{
23+
24+
25+
/**
26+
* Verify that a registered standard which doesn't have a "Sniffs" directory, but does have a file
27+
* called "Sniffs" doesn't result in any errors being thrown.
28+
*
29+
* @return void
30+
*/
31+
public function testSniffsFileNotDirectory()
32+
{
33+
// Set up the ruleset.
34+
$standard = __DIR__.'/ProcessRulesetInvalidNoSniffsDirTest.xml';
35+
$config = new ConfigDouble(["--standard=$standard"]);
36+
$ruleset = new Ruleset($config);
37+
38+
$expected = ['Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\BacktickOperatorSniff'];
39+
40+
$this->assertSame($expected, $ruleset->sniffCodes);
41+
42+
}//end testSniffsFileNotDirectory()
43+
44+
45+
/**
46+
* Verify that all sniffs in a registered standard included in a ruleset automatically get added.
47+
*
48+
* @return void
49+
*/
50+
public function testAutoExpandSniffsDirectory()
51+
{
52+
// Set up the ruleset.
53+
$standard = __DIR__.'/ProcessRulesetAutoExpandSniffsDirectoryTest.xml';
54+
$config = new ConfigDouble(["--standard=$standard"]);
55+
$ruleset = new Ruleset($config);
56+
57+
$std = 'TestStandard';
58+
$sniffDir = 'Fixtures\TestStandard\Sniffs';
59+
$expected = [
60+
"$std.Deprecated.WithLongReplacement" => "$sniffDir\Deprecated\WithLongReplacementSniff",
61+
"$std.Deprecated.WithReplacement" => "$sniffDir\Deprecated\WithReplacementSniff",
62+
"$std.Deprecated.WithReplacementContainingLinuxNewlines" => "$sniffDir\Deprecated\WithReplacementContainingLinuxNewlinesSniff",
63+
"$std.Deprecated.WithReplacementContainingNewlines" => "$sniffDir\Deprecated\WithReplacementContainingNewlinesSniff",
64+
"$std.Deprecated.WithoutReplacement" => "$sniffDir\Deprecated\WithoutReplacementSniff",
65+
"$std.DeprecatedInvalid.EmptyDeprecationVersion" => "$sniffDir\DeprecatedInvalid\EmptyDeprecationVersionSniff",
66+
"$std.DeprecatedInvalid.EmptyRemovalVersion" => "$sniffDir\DeprecatedInvalid\EmptyRemovalVersionSniff",
67+
"$std.DeprecatedInvalid.InvalidDeprecationMessage" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationMessageSniff",
68+
"$std.DeprecatedInvalid.InvalidDeprecationVersion" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationVersionSniff",
69+
"$std.DeprecatedInvalid.InvalidRemovalVersion" => "$sniffDir\DeprecatedInvalid\InvalidRemovalVersionSniff",
70+
"$std.SetProperty.AllowedAsDeclared" => "$sniffDir\SetProperty\AllowedAsDeclaredSniff",
71+
"$std.SetProperty.AllowedViaMagicMethod" => "$sniffDir\SetProperty\AllowedViaMagicMethodSniff",
72+
"$std.SetProperty.AllowedViaStdClass" => "$sniffDir\SetProperty\AllowedViaStdClassSniff",
73+
"$std.SetProperty.NotAllowedViaAttribute" => "$sniffDir\SetProperty\NotAllowedViaAttributeSniff",
74+
"$std.SetProperty.PropertyTypeHandling" => "$sniffDir\SetProperty\PropertyTypeHandlingSniff",
75+
];
76+
77+
// Sort the value to make the tests stable as different OSes will read directories
78+
// in a different order and the order is not relevant for these tests. Just the values.
79+
$actual = $ruleset->sniffCodes;
80+
ksort($actual);
81+
82+
$this->assertSame($expected, $actual);
83+
84+
}//end testAutoExpandSniffsDirectory()
85+
86+
87+
/**
88+
* Verify handling of exclusions of groups of sniffs after inclusion via an even larger "group".
89+
*
90+
* @return void
91+
*/
92+
public function testExcludeSniffGroup()
93+
{
94+
// Set up the ruleset.
95+
$standard = __DIR__.'/ProcessRulesetExcludeSniffGroupTest.xml';
96+
$config = new ConfigDouble(["--standard=$standard"]);
97+
$ruleset = new Ruleset($config);
98+
99+
$expected = [
100+
'PSR1.Classes.ClassDeclaration' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff',
101+
'PSR1.Methods.CamelCapsMethodName' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Methods\CamelCapsMethodNameSniff',
102+
];
103+
104+
// Sort the value to make the tests stable as different OSes will read directories
105+
// in a different order and the order is not relevant for these tests. Just the values.
106+
$actual = $ruleset->sniffCodes;
107+
ksort($actual);
108+
109+
$this->assertSame($expected, $actual);
110+
111+
}//end testExcludeSniffGroup()
112+
113+
114+
/*
115+
* No test for <ini> without "name" as there is nothing we can assert to verify it's being ignored.
116+
*/
117+
118+
119+
/**
120+
* Test that an `<ini>` directive without a "value" attribute will be set to the ini equivalent of `true`.
121+
*
122+
* @return void
123+
*/
124+
public function testIniWithoutValue()
125+
{
126+
$originalValue = ini_get('user_agent');
127+
128+
// Set up the ruleset.
129+
$this->getMiscRuleset();
130+
131+
$actualValue = ini_get('user_agent');
132+
// Reset the ini to its original value before the assertion to ensure it's never left in an incorrect state.
133+
if ($originalValue !== false) {
134+
ini_set('user_agent', $originalValue);
135+
}
136+
137+
$this->assertSame('1', $actualValue);
138+
139+
}//end testIniWithoutValue()
140+
141+
142+
/**
143+
* Verify that inclusion of a single error code:
144+
* - Includes the sniff, but sets "severity" for the sniff to 0;
145+
* - Sets "severity" for the specific error code included to 5.;
146+
*
147+
* @return void
148+
*/
149+
public function testIncludeSingleErrorCode()
150+
{
151+
// Set up the ruleset.
152+
$ruleset = $this->getMiscRuleset();
153+
154+
$key = 'severity';
155+
156+
$sniffCode = 'Generic.PHP.RequireStrictTypes';
157+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
158+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
159+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
160+
$this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
161+
162+
$sniffCode = 'Generic.PHP.RequireStrictTypes.MissingDeclaration';
163+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
164+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
165+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
166+
$this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
167+
168+
}//end testIncludeSingleErrorCode()
169+
170+
171+
/**
172+
* Verify that if all error codes, save one, from a sniff were previously excluded, an include for an additional
173+
* error code from that same sniff will be respected.
174+
*
175+
* @return void
176+
*/
177+
public function testErrorCodeIncludeAfterExclude()
178+
{
179+
// Set up the ruleset.
180+
$ruleset = $this->getMiscRuleset();
181+
182+
$key = 'severity';
183+
184+
$sniffCode = 'PEAR.Files.IncludingFile';
185+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
186+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
187+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
188+
$this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
189+
190+
$sniffCode = 'PEAR.Files.IncludingFile.BracketsNotRequired';
191+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
192+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
193+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
194+
$this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
195+
196+
$sniffCode = 'PEAR.Files.IncludingFile.UseRequire';
197+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
198+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
199+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
200+
$this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
201+
202+
}//end testErrorCodeIncludeAfterExclude()
203+
204+
205+
/**
206+
* Verify that a <rule> element without a "ref" is completely ignored.
207+
*
208+
* @return void
209+
*/
210+
public function testRuleWithoutRefIsIgnored()
211+
{
212+
// Set up the ruleset.
213+
$ruleset = $this->getMiscRuleset();
214+
215+
$sniffCode = 'Generic.Metrics.CyclomaticComplexity';
216+
$this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode registered");
217+
$this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted");
218+
219+
}//end testRuleWithoutRefIsIgnored()
220+
221+
222+
/**
223+
* Verify that no "ruleset adjustments" are registered via an `<exclude>` without a "name".
224+
*
225+
* @return void
226+
*/
227+
public function testRuleExcludeWithoutNameIsIgnored()
228+
{
229+
// Set up the ruleset.
230+
$ruleset = $this->getMiscRuleset();
231+
232+
$sniffCode = 'Generic.PHP.BacktickOperator';
233+
$this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode not registered");
234+
$this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted");
235+
236+
$sniffCode = 'Generic.PHP.BacktickOperator.Found';
237+
$this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted");
238+
239+
}//end testRuleExcludeWithoutNameIsIgnored()
240+
241+
242+
/**
243+
* Test Helper.
244+
*
245+
* @return \PHP_CodeSniffer\Sniffs\Sniff
246+
*/
247+
private function getMiscRuleset()
248+
{
249+
static $ruleset;
250+
251+
if (isset($ruleset) === false) {
252+
// Set up the ruleset.
253+
$standard = __DIR__.'/ProcessRulesetMiscTest.xml';
254+
$config = new ConfigDouble(["--standard=$standard"]);
255+
$ruleset = new Ruleset($config);
256+
}
257+
258+
return $ruleset;
259+
260+
}//end getMiscRuleset()
261+
262+
263+
}//end class

0 commit comments

Comments
 (0)