Skip to content

Commit 158fc64

Browse files
committed
Ruleset::processRuleset(); add various tests for things not already covered
Mostly testing error handling and the handling of edge cases.
1 parent ee7034b commit 158fc64

File tree

7 files changed

+316
-0
lines changed

7 files changed

+316
-0
lines changed

tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
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>
Lines changed: 8 additions & 0 deletions
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>
Lines changed: 11 additions & 0 deletions
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+
Lines changed: 10 additions & 0 deletions
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>
Lines changed: 25 additions & 0 deletions
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>
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
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.WithoutReplacement" => "$sniffDir\Deprecated\WithoutReplacementSniff",
62+
"$std.Deprecated.WithReplacementContainingLinuxNewlines" => "$sniffDir\Deprecated\WithReplacementContainingLinuxNewlinesSniff",
63+
"$std.Deprecated.WithReplacementContainingNewlines" => "$sniffDir\Deprecated\WithReplacementContainingNewlinesSniff",
64+
"$std.Deprecated.WithReplacement" => "$sniffDir\Deprecated\WithReplacementSniff",
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+
$this->assertSame($expected, $ruleset->sniffCodes);
105+
106+
}//end testExcludeSniffGroup()
107+
108+
109+
/*
110+
* No test for <ini> without "name" as there is nothing we can assert to verify it's being ignored.
111+
*/
112+
113+
114+
/**
115+
* Test that an `<ini>` directive without a "value" attribute will be set to the ini equivalent of `true`.
116+
*
117+
* @return void
118+
*/
119+
public function testIniWithoutValue()
120+
{
121+
$originalValue = ini_get('user_agent');
122+
123+
// Set up the ruleset.
124+
$this->getMiscRuleset();
125+
126+
$actualValue = ini_get('user_agent');
127+
// Reset the ini to its original value before the assertion to ensure it's never left in an incorrect state.
128+
if ($originalValue !== false) {
129+
ini_set('user_agent', $originalValue);
130+
}
131+
132+
$this->assertSame('1', $actualValue);
133+
134+
}//end testIniWithoutValue()
135+
136+
137+
/**
138+
* Verify that inclusion of a single error code:
139+
* - Includes the sniff, but sets "severity" for the sniff to 0;
140+
* - Sets "severity" for the specific error code included to 5.;
141+
*
142+
* @return void
143+
*/
144+
public function testIncludeSingleErrorCode()
145+
{
146+
// Set up the ruleset.
147+
$ruleset = $this->getMiscRuleset();
148+
149+
$key = 'severity';
150+
151+
$sniffCode = 'Generic.PHP.RequireStrictTypes';
152+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
153+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
154+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
155+
$this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
156+
157+
$sniffCode = 'Generic.PHP.RequireStrictTypes.MissingDeclaration';
158+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
159+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
160+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
161+
$this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
162+
163+
}//end testIncludeSingleErrorCode()
164+
165+
166+
/**
167+
* Verify that if all error codes, save one, from a sniff were previously excluded, an include for an additional
168+
* error code from that same sniff will be respected.
169+
*
170+
* @return void
171+
*/
172+
public function testErrorCodeIncludeAfterExclude()
173+
{
174+
// Set up the ruleset.
175+
$ruleset = $this->getMiscRuleset();
176+
177+
$key = 'severity';
178+
179+
$sniffCode = 'PEAR.Files.IncludingFile';
180+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
181+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
182+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
183+
$this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
184+
185+
$sniffCode = 'PEAR.Files.IncludingFile.BracketsNotRequired';
186+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
187+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
188+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
189+
$this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
190+
191+
$sniffCode = 'PEAR.Files.IncludingFile.UseRequire';
192+
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
193+
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
194+
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
195+
$this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");
196+
197+
}//end testErrorCodeIncludeAfterExclude()
198+
199+
200+
/**
201+
* Verify that a <rule> element without a "ref" is completely ignored.
202+
*
203+
* @return void
204+
*/
205+
public function testRuleWithoutRefIsIgnored()
206+
{
207+
// Set up the ruleset.
208+
$ruleset = $this->getMiscRuleset();
209+
210+
$sniffCode = 'Generic.Metrics.CyclomaticComplexity';
211+
$this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode registered");
212+
$this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted");
213+
214+
}//end testRuleWithoutRefIsIgnored()
215+
216+
217+
/**
218+
* Verify that no "ruleset adjustments" are registered via an `<exclude>` without a "name".
219+
*
220+
* @return void
221+
*/
222+
public function testRuleExcludeWithoutNameIsIgnored()
223+
{
224+
// Set up the ruleset.
225+
$ruleset = $this->getMiscRuleset();
226+
227+
$sniffCode = 'Generic.PHP.BacktickOperator';
228+
$this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode not registered");
229+
$this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted");
230+
231+
$sniffCode = 'Generic.PHP.BacktickOperator.Found';
232+
$this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted");
233+
234+
}//end testRuleExcludeWithoutNameIsIgnored()
235+
236+
237+
/**
238+
* Test Helper.
239+
*
240+
* @return \PHP_CodeSniffer\Sniffs\Sniff
241+
*/
242+
private function getMiscRuleset()
243+
{
244+
static $ruleset;
245+
246+
if (isset($ruleset) === false) {
247+
// Set up the ruleset.
248+
$standard = __DIR__.'/ProcessRulesetMiscTest.xml';
249+
$config = new ConfigDouble(["--standard=$standard"]);
250+
$ruleset = new Ruleset($config);
251+
}
252+
253+
return $ruleset;
254+
255+
}//end getMiscRuleset()
256+
257+
258+
}//end class

0 commit comments

Comments
 (0)