From 71b452422dbeb2dd44ce7daad8d1fcc14094bcfc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 12 Nov 2024 16:18:10 +0100 Subject: [PATCH] Common::getSniffCode(): be more lenient about sniffs not following naming conventions Sniff classes _should_ always follow the directory layout and naming conventions for sniffs as per the [Tutorial](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Coding-Standard-Tutorial). However, before the change made in 524, when given a sniff class name for a sniff not following the naming conventions, the `Common::getSniffCode()` method would return a "sniff code" anyway. And even though the sniff code would be unconventional and not really valid, it would still _work_. Since 524 this is no longer the case. Given the above, the change from 524 breaks custom rulesets which use `` includes for individual sniff files not complying with the naming conventions. Breaking changes can only be made in majors, so this commit reverts the problematic part of the change from 524. Includes additional tests safeguarding the (broken) behaviour which needs to be maintained until the next major. Fixes 675 --- src/Util/Common.php | 20 +++++----- tests/Core/Util/Common/GetSniffCodeTest.php | 41 +++++++++++++++++---- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/Util/Common.php b/src/Util/Common.php index af4aba69fd..cb6965f62c 100644 --- a/src/Util/Common.php +++ b/src/Util/Common.php @@ -542,13 +542,7 @@ public static function getSniffCode($sniffClass) $parts = explode('\\', $sniffClass); $partsCount = count($parts); - if ($partsCount < 4) { - throw new InvalidArgumentException( - 'The $sniffClass parameter was not passed a fully qualified sniff(test) class name. Received: '.$sniffClass - ); - } - - $sniff = $parts[($partsCount - 1)]; + $sniff = $parts[($partsCount - 1)]; if (substr($sniff, -5) === 'Sniff') { // Sniff class name. @@ -562,8 +556,16 @@ public static function getSniffCode($sniffClass) ); } - $standard = $parts[($partsCount - 4)]; - $category = $parts[($partsCount - 2)]; + $standard = ''; + if (isset($parts[($partsCount - 4)]) === true) { + $standard = $parts[($partsCount - 4)]; + } + + $category = ''; + if (isset($parts[($partsCount - 2)]) === true) { + $category = $parts[($partsCount - 2)]; + } + return $standard.'.'.$category.'.'.$sniff; }//end getSniffCode() diff --git a/tests/Core/Util/Common/GetSniffCodeTest.php b/tests/Core/Util/Common/GetSniffCodeTest.php index 7cf9b16edf..48161f1ce2 100644 --- a/tests/Core/Util/Common/GetSniffCodeTest.php +++ b/tests/Core/Util/Common/GetSniffCodeTest.php @@ -108,7 +108,6 @@ public static function dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTes 'Unqualified class name' => ['ClassName'], 'Fully qualified class name, not enough parts' => ['Fully\\Qualified\\ClassName'], 'Fully qualified class name, doesn\'t end on Sniff or UnitTest' => ['Fully\\Sniffs\\Qualified\\ClassName'], - 'Fully qualified class name, ends on Sniff, but isn\'t' => ['Fully\\Sniffs\\AbstractSomethingSniff'], ]; }//end dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() @@ -141,30 +140,58 @@ public function testGetSniffCode($fqnClass, $expected) public static function dataGetSniffCode() { return [ - 'PHPCS native sniff' => [ + 'PHPCS native sniff' => [ 'fqnClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Arrays\\ArrayIndentSniff', 'expected' => 'Generic.Arrays.ArrayIndent', ], - 'Class is a PHPCS native test class' => [ + 'Class is a PHPCS native test class' => [ 'fqnClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Tests\\Arrays\\ArrayIndentUnitTest', 'expected' => 'Generic.Arrays.ArrayIndent', ], - 'Sniff in external standard without namespace prefix' => [ + 'Sniff in external standard without namespace prefix' => [ 'fqnClass' => 'MyStandard\\Sniffs\\PHP\\MyNameSniff', 'expected' => 'MyStandard.PHP.MyName', ], - 'Test in external standard without namespace prefix' => [ + 'Test in external standard without namespace prefix' => [ 'fqnClass' => 'MyStandard\\Tests\\PHP\\MyNameSniff', 'expected' => 'MyStandard.PHP.MyName', ], - 'Sniff in external standard with namespace prefix' => [ + 'Sniff in external standard with namespace prefix' => [ 'fqnClass' => 'Vendor\\Package\\MyStandard\\Sniffs\\Category\\AnalyzeMeSniff', 'expected' => 'MyStandard.Category.AnalyzeMe', ], - 'Test in external standard with namespace prefix' => [ + 'Test in external standard with namespace prefix' => [ 'fqnClass' => 'Vendor\\Package\\MyStandard\\Tests\\Category\\AnalyzeMeUnitTest', 'expected' => 'MyStandard.Category.AnalyzeMe', ], + + /* + * These are not valid sniff codes and is an undesirable result, but can't be helped + * as changing this would be a BC-break. + * Supporting these to allow for tags directly including sniff files. + * See: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/675 + */ + + 'Fully qualified class name, ends on Sniff, but isn\'t' => [ + 'fqnClass' => 'Fully\\Sniffs\\AbstractSomethingSniff', + 'expected' => '.Sniffs.AbstractSomething', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [1]' => [ + 'fqnClass' => 'CheckMeSniff', + 'expected' => '..CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [2]' => [ + 'fqnClass' => 'CompanyName\\CheckMeSniff', + 'expected' => '.CompanyName.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [3]' => [ + 'fqnClass' => 'CompanyName\\Sniffs\\CheckMeSniff', + 'expected' => '.Sniffs.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [4]' => [ + 'fqnClass' => 'CompanyName\\CustomSniffs\\Whatever\\CheckMeSniff', + 'expected' => 'CompanyName.Whatever.CheckMe', + ], ]; }//end dataGetSniffCode()