diff --git a/tests/Core/Ruleset/ConstructorNoSniffsTest.xml b/tests/Core/Ruleset/ConstructorNoSniffsTest.xml new file mode 100644 index 0000000000..77ae02580b --- /dev/null +++ b/tests/Core/Ruleset/ConstructorNoSniffsTest.xml @@ -0,0 +1,6 @@ + + + + . + + diff --git a/tests/Core/Ruleset/ConstructorTest.php b/tests/Core/Ruleset/ConstructorTest.php new file mode 100644 index 0000000000..a0b3ab3088 --- /dev/null +++ b/tests/Core/Ruleset/ConstructorTest.php @@ -0,0 +1,293 @@ + + * @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\Autoload; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test various aspects of the Ruleset::__construct() method not covered via other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::__construct + */ +final class ConstructorTest extends AbstractRulesetTestCase +{ + + + /** + * Test setting the ruleset name. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param string $expected The expected set ruleset name. + * + * @dataProvider dataHandlingStandardsPassedViaCLI + * + * @return void + */ + public function testHandlingStandardsPassedViaCLI($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + $ruleset = new Ruleset($config); + + $this->assertSame($expected, $ruleset->name); + + }//end testHandlingStandardsPassedViaCLI() + + + /** + * Data provider. + * + * @see testHandlingStandardsPassedViaCLI() + * + * @return array>> + */ + public static function dataHandlingStandardsPassedViaCLI() + { + return [ + 'Single standard passed' => [ + 'cliArgs' => ['--standard=PSR1'], + 'expected' => 'PSR1', + ], + 'Multiple standards passed' => [ + 'cliArgs' => ['--standard=PSR1,Zend'], + 'expected' => 'PSR1, Zend', + ], + 'Absolute path to standard directory passed' => [ + 'cliArgs' => [ + '--standard='.__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard', + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => 'TestStandard', + ], + ]; + + }//end dataHandlingStandardsPassedViaCLI() + + + /** + * Verify that standards are registered with the Autoloader. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param array $expected Minimum set of standards expected to be registered with the autoloader. + * + * @dataProvider dataStandardsAreRegisteredWithAutoloader + * + * @return void + */ + public function testStandardsAreRegisteredWithAutoloader($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + new Ruleset($config); + + $autoloadPaths = Autoload::getSearchPaths(); + + // Note: doing a full comparison of the Autoloader registered standards would make this test unstable + // as the `CodeSniffer.conf` of the user running the tests could interfer if they have additional + // external standards registered. + // Also note that `--runtime-set` is being used to set `installed_paths` to prevent making any changes to + // the `CodeSniffer.conf` file of the user running the tests. + foreach ($expected as $path => $namespacedStandardName) { + $this->assertArrayHasKey($path, $autoloadPaths, "Path $path has not been registered with the autoloader"); + $this->assertSame($namespacedStandardName, $autoloadPaths[$path], 'Expected (namespaced) standard name does not match'); + } + + }//end testStandardsAreRegisteredWithAutoloader() + + + /** + * Data provider. + * + * @see testStandardsAreRegisteredWithAutoloader() + * + * @return array>> + */ + public static function dataStandardsAreRegisteredWithAutoloader() + { + $basePath = dirname(dirname(dirname(__DIR__))).DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Standards'.DIRECTORY_SEPARATOR; + $defaultPaths = [ + $basePath.'MySource' => 'MySource', + $basePath.'PEAR' => 'PEAR', + $basePath.'PSR1' => 'PSR1', + $basePath.'PSR12' => 'PSR12', + $basePath.'PSR2' => 'PSR2', + $basePath.'Squiz' => 'Squiz', + $basePath.'Zend' => 'Zend', + ]; + + $data = [ + 'Default standards' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--runtime-set installed_paths .', + ], + 'expected' => $defaultPaths, + ], + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'DirectoryExpansion'; + $extraInstalledPath .= DIRECTORY_SEPARATOR.'.hiddenAbove'.DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'MyStandard'; + $data['Additional non-namespaced standard'] = [ + 'cliArgs' => [ + '--standard=MyStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'MyStandard']), + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard'; + $data['Additional namespaced standard'] = [ + 'cliArgs' => [ + '--standard=TestStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'Fixtures\TestStandard']), + ]; + + return $data; + + }//end dataStandardsAreRegisteredWithAutoloader() + + + /** + * Verify handling of sniff restrictions in combination with the caching setting. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param bool $cache Whether to turn the cache on or off. + * @param array $expected Sniffs which are expected to have been registered. + * + * @dataProvider dataCachingVersusRestrictions + * + * @return void + */ + public function testCachingVersusRestrictions($cliArgs, $cache, $expected) + { + $config = new ConfigDouble($cliArgs); + + // Overrule the cache setting (which is being ignored in the Config when the tests are running). + $config->cache = $cache; + + $ruleset = new Ruleset($config); + + $actual = array_keys($ruleset->sniffs); + sort($actual); + + $this->assertSame($expected, $actual); + + }//end testCachingVersusRestrictions() + + + /** + * Data provider. + * + * Note: the test cases only use `--exclude` to restrict, + * + * @see testCachingVersusRestrictions() + * + * @return array>> + */ + public static function dataCachingVersusRestrictions() + { + $completeSet = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ]; + + return [ + 'No restrictions, cache off' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => false, + 'expected' => $completeSet, + ], + 'Has exclusions, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ], + ], + 'Has sniff selection, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--sniffs=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + ], + ], + 'No restrictions, cache on' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => true, + 'expected' => $completeSet, + ], + 'Has exclusions, cache on' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowAlternativePHPTags,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects', + ], + 'cache' => true, + 'expected' => $completeSet, + ], + + /* + * "Has sniff selection, cache on" case cannot be tested due to the `Ruleset` class + * containing special handling of sniff selection when the tests are running. + */ + + ]; + + }//end dataCachingVersusRestrictions() + + + /** + * Test an exception is thrown when no sniffs have been registered via the ruleset. + * + * @return void + */ + public function testNoSniffsRegisteredException() + { + $standard = __DIR__.'/ConstructorNoSniffsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $message = 'No sniffs were registered'; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testNoSniffsRegisteredException() + + +}//end class