Skip to content

Commit

Permalink
Ruleset::processRuleset(); add various tests for things not already c…
Browse files Browse the repository at this point in the history
…overed

Mostly testing error handling and the handling of edge cases.
  • Loading branch information
jrfnl committed Dec 7, 2024
1 parent a171348 commit c7cf1e5
Show file tree
Hide file tree
Showing 7 changed files with 321 additions and 0 deletions.
Empty file.
4 changes: 4 additions & 0 deletions tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="InvalidNoSniffsDir" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">

</ruleset>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">

<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>

<rule ref="TestStandard"/>

</ruleset>
11 changes: 11 additions & 0 deletions tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">

<rule ref="PSR1">
<exclude name="Generic"/>
<exclude name="PSR1.Files"/>
<exclude name="Squiz.Classes.ValidClassName"/>
</rule>

</ruleset>

10 changes: 10 additions & 0 deletions tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">

<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/"/>

<rule ref="InvalidNoSniffsDir"/>

<!-- Prevent a "no sniff were registered" error. -->
<rule ref="Generic.PHP.BacktickOperator"/>
</ruleset>
25 changes: 25 additions & 0 deletions tests/Core/Ruleset/ProcessRulesetMiscTest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">

<!-- Error handling: Ini missing "name" will be ignored. -->
<ini value="2"/>

<!-- Error handling: Ini missing "value" will be set to true. -->
<ini name="user_agent"/>

<!-- Include of error code after previous exclude of most of a sniff via another error code include. -->
<rule ref="PEAR.Files.IncludingFile.BracketsNotRequired"/>
<rule ref="PEAR.Files.IncludingFile.UseRequire"/>

<!-- Include single error code. -->
<rule ref="Generic.PHP.RequireStrictTypes.MissingDeclaration"/>

<!-- Error handling: Rule without ref. -->
<rule name="Generic.Metrics.CyclomaticComplexity"/>

<!-- Error handling: Exclude without name. -->
<rule ref="Generic.PHP.BacktickOperator">
<exclude ref="Generic.PHP.BacktickOperator.Found"/>
</rule>

</ruleset>
263 changes: 263 additions & 0 deletions tests/Core/Ruleset/ProcessRulesetTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
<?php
/**
* Test the Ruleset::processRuleset() method.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2024 PHPCSStandards and contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/

namespace PHP_CodeSniffer\Tests\Core\Ruleset;

use PHP_CodeSniffer\Ruleset;
use PHP_CodeSniffer\Tests\ConfigDouble;
use PHPUnit\Framework\TestCase;

/**
* Test various aspects of the Ruleset::processRuleset() method not covered via other tests.
*
* @covers \PHP_CodeSniffer\Ruleset::processRuleset
*/
final class ProcessRulesetTest extends TestCase
{


/**
* Verify that a registered standard which doesn't have a "Sniffs" directory, but does have a file
* called "Sniffs" doesn't result in any errors being thrown.
*
* @return void
*/
public function testSniffsFileNotDirectory()
{
// Set up the ruleset.
$standard = __DIR__.'/ProcessRulesetInvalidNoSniffsDirTest.xml';
$config = new ConfigDouble(["--standard=$standard"]);
$ruleset = new Ruleset($config);

$expected = ['Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\BacktickOperatorSniff'];

$this->assertSame($expected, $ruleset->sniffCodes);

}//end testSniffsFileNotDirectory()


/**
* Verify that all sniffs in a registered standard included in a ruleset automatically get added.
*
* @return void
*/
public function testAutoExpandSniffsDirectory()
{
// Set up the ruleset.
$standard = __DIR__.'/ProcessRulesetAutoExpandSniffsDirectoryTest.xml';
$config = new ConfigDouble(["--standard=$standard"]);
$ruleset = new Ruleset($config);

$std = 'TestStandard';
$sniffDir = 'Fixtures\TestStandard\Sniffs';
$expected = [
"$std.Deprecated.WithLongReplacement" => "$sniffDir\Deprecated\WithLongReplacementSniff",
"$std.Deprecated.WithReplacement" => "$sniffDir\Deprecated\WithReplacementSniff",
"$std.Deprecated.WithReplacementContainingLinuxNewlines" => "$sniffDir\Deprecated\WithReplacementContainingLinuxNewlinesSniff",
"$std.Deprecated.WithReplacementContainingNewlines" => "$sniffDir\Deprecated\WithReplacementContainingNewlinesSniff",
"$std.Deprecated.WithoutReplacement" => "$sniffDir\Deprecated\WithoutReplacementSniff",
"$std.DeprecatedInvalid.EmptyDeprecationVersion" => "$sniffDir\DeprecatedInvalid\EmptyDeprecationVersionSniff",
"$std.DeprecatedInvalid.EmptyRemovalVersion" => "$sniffDir\DeprecatedInvalid\EmptyRemovalVersionSniff",
"$std.DeprecatedInvalid.InvalidDeprecationMessage" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationMessageSniff",
"$std.DeprecatedInvalid.InvalidDeprecationVersion" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationVersionSniff",
"$std.DeprecatedInvalid.InvalidRemovalVersion" => "$sniffDir\DeprecatedInvalid\InvalidRemovalVersionSniff",
"$std.SetProperty.AllowedAsDeclared" => "$sniffDir\SetProperty\AllowedAsDeclaredSniff",
"$std.SetProperty.AllowedViaMagicMethod" => "$sniffDir\SetProperty\AllowedViaMagicMethodSniff",
"$std.SetProperty.AllowedViaStdClass" => "$sniffDir\SetProperty\AllowedViaStdClassSniff",
"$std.SetProperty.NotAllowedViaAttribute" => "$sniffDir\SetProperty\NotAllowedViaAttributeSniff",
"$std.SetProperty.PropertyTypeHandling" => "$sniffDir\SetProperty\PropertyTypeHandlingSniff",
];

// Sort the value to make the tests stable as different OSes will read directories
// in a different order and the order is not relevant for these tests. Just the values.
$actual = $ruleset->sniffCodes;
ksort($actual);

$this->assertSame($expected, $actual);

}//end testAutoExpandSniffsDirectory()


/**
* Verify handling of exclusions of groups of sniffs after inclusion via an even larger "group".
*
* @return void
*/
public function testExcludeSniffGroup()
{
// Set up the ruleset.
$standard = __DIR__.'/ProcessRulesetExcludeSniffGroupTest.xml';
$config = new ConfigDouble(["--standard=$standard"]);
$ruleset = new Ruleset($config);

$expected = [
'PSR1.Classes.ClassDeclaration' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff',
'PSR1.Methods.CamelCapsMethodName' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Methods\CamelCapsMethodNameSniff',
];

// Sort the value to make the tests stable as different OSes will read directories
// in a different order and the order is not relevant for these tests. Just the values.
$actual = $ruleset->sniffCodes;
ksort($actual);

$this->assertSame($expected, $actual);

}//end testExcludeSniffGroup()


/*
* No test for <ini> without "name" as there is nothing we can assert to verify it's being ignored.
*/


/**
* Test that an `<ini>` directive without a "value" attribute will be set to the ini equivalent of `true`.
*
* @return void
*/
public function testIniWithoutValue()
{
$originalValue = ini_get('user_agent');

// Set up the ruleset.
$this->getMiscRuleset();

$actualValue = ini_get('user_agent');
// Reset the ini to its original value before the assertion to ensure it's never left in an incorrect state.
if ($originalValue !== false) {
ini_set('user_agent', $originalValue);
}

$this->assertSame('1', $actualValue);

}//end testIniWithoutValue()


/**
* Verify that inclusion of a single error code:
* - Includes the sniff, but sets "severity" for the sniff to 0;
* - Sets "severity" for the specific error code included to 5.;
*
* @return void
*/
public function testIncludeSingleErrorCode()
{
// Set up the ruleset.
$ruleset = $this->getMiscRuleset();

$key = 'severity';

$sniffCode = 'Generic.PHP.RequireStrictTypes';
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
$this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");

$sniffCode = 'Generic.PHP.RequireStrictTypes.MissingDeclaration';
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
$this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");

}//end testIncludeSingleErrorCode()


/**
* Verify that if all error codes, save one, from a sniff were previously excluded, an include for an additional
* error code from that same sniff will be respected.
*
* @return void
*/
public function testErrorCodeIncludeAfterExclude()
{
// Set up the ruleset.
$ruleset = $this->getMiscRuleset();

$key = 'severity';

$sniffCode = 'PEAR.Files.IncludingFile';
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
$this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");

$sniffCode = 'PEAR.Files.IncludingFile.BracketsNotRequired';
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
$this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");

$sniffCode = 'PEAR.Files.IncludingFile.UseRequire';
$this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered");
$this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array");
$this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode");
$this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode");

}//end testErrorCodeIncludeAfterExclude()


/**
* Verify that a <rule> element without a "ref" is completely ignored.
*
* @return void
*/
public function testRuleWithoutRefIsIgnored()
{
// Set up the ruleset.
$ruleset = $this->getMiscRuleset();

$sniffCode = 'Generic.Metrics.CyclomaticComplexity';
$this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode registered");
$this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted");

}//end testRuleWithoutRefIsIgnored()


/**
* Verify that no "ruleset adjustments" are registered via an `<exclude>` without a "name".
*
* @return void
*/
public function testRuleExcludeWithoutNameIsIgnored()
{
// Set up the ruleset.
$ruleset = $this->getMiscRuleset();

$sniffCode = 'Generic.PHP.BacktickOperator';
$this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode not registered");
$this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted");

$sniffCode = 'Generic.PHP.BacktickOperator.Found';
$this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted");

}//end testRuleExcludeWithoutNameIsIgnored()


/**
* Test Helper.
*
* @return \PHP_CodeSniffer\Sniffs\Sniff
*/
private function getMiscRuleset()
{
static $ruleset;

if (isset($ruleset) === false) {
// Set up the ruleset.
$standard = __DIR__.'/ProcessRulesetMiscTest.xml';
$config = new ConfigDouble(["--standard=$standard"]);
$ruleset = new Ruleset($config);
}

return $ruleset;

}//end getMiscRuleset()


}//end class

0 comments on commit c7cf1e5

Please sign in to comment.