Skip to content

Commit 3012889

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 3012889

File tree

7 files changed

+311
-0
lines changed

7 files changed

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

0 commit comments

Comments
 (0)