From 577b627662a61a350766588759297d36e0591cc1 Mon Sep 17 00:00:00 2001 From: Martin Hujer Date: Mon, 15 May 2017 22:01:44 +0200 Subject: [PATCH 1/3] Exception name must end with Exception --- .../Exceptions/ExceptionDeclarationSniff.php | 56 ++++++++++ .../ExceptionDeclarationSniffTest.php | 102 ++++++++++++++++++ .../data/AbstractExceptionWithInvalidName.php | 10 ++ ...bstractExceptionWithValidNameException.php | 10 ++ .../data/ClassThatDoesNotExtendAnything.php | 10 ++ .../data/ClassThatDoesNotExtendException.php | 10 ++ .../InterfaceThatDoesNotExtendAnything.php | 12 +++ ...faceThatDoesNotExtendAnythingException.php | 12 +++ .../data/InterfaceThatExtendsException.php | 12 +++ ...rfaceThatExtendsExceptionIncorrectName.php | 12 +++ .../Exceptions/data/InvalidExceptionName.php | 10 ++ ...lidClassNameThatExtendsCustomException.php | 10 ++ .../Exceptions/data/ValidNameException.php | 10 ++ 13 files changed, 276 insertions(+) create mode 100644 Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php create mode 100644 tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php create mode 100644 tests/Sniffs/Exceptions/data/AbstractExceptionWithInvalidName.php create mode 100644 tests/Sniffs/Exceptions/data/AbstractExceptionWithValidNameException.php create mode 100644 tests/Sniffs/Exceptions/data/ClassThatDoesNotExtendAnything.php create mode 100644 tests/Sniffs/Exceptions/data/ClassThatDoesNotExtendException.php create mode 100644 tests/Sniffs/Exceptions/data/InterfaceThatDoesNotExtendAnything.php create mode 100644 tests/Sniffs/Exceptions/data/InterfaceThatDoesNotExtendAnythingException.php create mode 100644 tests/Sniffs/Exceptions/data/InterfaceThatExtendsException.php create mode 100644 tests/Sniffs/Exceptions/data/InterfaceThatExtendsExceptionIncorrectName.php create mode 100644 tests/Sniffs/Exceptions/data/InvalidExceptionName.php create mode 100644 tests/Sniffs/Exceptions/data/ValidClassNameThatExtendsCustomException.php create mode 100644 tests/Sniffs/Exceptions/data/ValidNameException.php diff --git a/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php b/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php new file mode 100644 index 0000000..2fa844d --- /dev/null +++ b/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php @@ -0,0 +1,56 @@ +findExtendedClassName($classPointer); + if ($extendedClassName === false) { + return; //does not extend anything + } + + if (!StringHelper::endsWith($extendedClassName, 'Exception')) { + return; // does not extend Exception, is not an exception + } + + $this->checkExceptionName($phpcsFile, $classPointer); + } + + private function checkExceptionName(PhpCsFile $phpcsFile, int $classPointer) + { + $className = ClassHelper::getName($phpcsFile, $classPointer); + if (!StringHelper::endsWith($className, 'Exception')) { + $phpcsFile->addError(sprintf( + 'Exception class name "%s" must end with "Exception".', + $className + ), $classPointer, self::CODE_NOT_ENDING_WITH_EXCEPTION); + } + } + +} diff --git a/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php b/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php new file mode 100644 index 0000000..50b6e75 --- /dev/null +++ b/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php @@ -0,0 +1,102 @@ +checkFile(__DIR__ . '/data/InvalidExceptionName.php'); + + $this->assertSniffError( + $resultFile, + 7, + ExceptionDeclarationSniff::CODE_NOT_ENDING_WITH_EXCEPTION, + 'Exception class name "InvalidExceptionName" must end with "Exception".' + ); + } + + public function testValidClassName() + { + $resultFile = $this->checkFile(__DIR__ . '/data/ValidNameException.php'); + + $this->assertNoSniffError($resultFile, 7); + } + + public function testValidClassNameThatExtendsCustomException() + { + $resultFile = $this->checkFile(__DIR__ . '/data/ValidClassNameThatExtendsCustomException.php'); + + $this->assertNoSniffError($resultFile, 7); + } + + public function testAbstractExceptionWithValidNameException() + { + $resultFile = $this->checkFile(__DIR__ . '/data/AbstractExceptionWithValidNameException.php'); + + $this->assertNoSniffError($resultFile, 7); + } + + public function testAbstractClassWithInvalidExceptionName() + { + $resultFile = $this->checkFile(__DIR__ . '/data/AbstractExceptionWithInvalidName.php'); + + $this->assertSniffError( + $resultFile, + 7, + ExceptionDeclarationSniff::CODE_NOT_ENDING_WITH_EXCEPTION, + 'Exception class name "AbstractExceptionWithInvalidName" must end with "Exception".' + ); + } + + public function testClassThatDoesNotExtendAnything() + { + $resultFile = $this->checkFile(__DIR__ . '/data/ClassThatDoesNotExtendAnything.php'); + + $this->assertNoSniffError($resultFile, 7); + } + + public function testClassThatExtendsRegularClass() + { + $resultFile = $this->checkFile(__DIR__ . '/data/ClassThatDoesNotExtendException.php'); + + $this->assertNoSniffError($resultFile, 7); + } + + public function testInterfaceThatDoesNotExtendAnything() + { + $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatDoesNotExtendAnything.php'); + + $this->assertNoSniffError($resultFile, 7); + } + + public function testInterfaceThatDoesNotExtendAnythingException() + { + $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatDoesNotExtendAnythingException.php'); + + $this->assertNoSniffError($resultFile, 7); + } + + public function testInterfaceThatExtendsException() + { + $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatExtendsException.php'); + + $this->assertNoSniffError($resultFile, 7); + } + + public function testInterfaceThatExtendsExceptionIncorrectName() + { + $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatExtendsExceptionIncorrectName.php'); + + $this->assertSniffError( + $resultFile, + 7, + ExceptionDeclarationSniff::CODE_NOT_ENDING_WITH_EXCEPTION, + 'Exception class name "InterfaceThatExtendsExceptionIncorrectName" must end with "Exception".' + ); + } + +} diff --git a/tests/Sniffs/Exceptions/data/AbstractExceptionWithInvalidName.php b/tests/Sniffs/Exceptions/data/AbstractExceptionWithInvalidName.php new file mode 100644 index 0000000..a76be7f --- /dev/null +++ b/tests/Sniffs/Exceptions/data/AbstractExceptionWithInvalidName.php @@ -0,0 +1,10 @@ + Date: Sun, 25 Jun 2017 18:06:26 +0200 Subject: [PATCH 2/3] Exception must be chainable --- .../Exceptions/ExceptionDeclarationSniff.php | 59 +++++++++++++++++++ .../ExceptionDeclarationSniffTest.php | 43 ++++++++++++++ .../data/ChainableConstructorException.php | 15 +++++ .../ConstructWithoutParametersException.php | 15 +++++ .../data/NonChainableConstructorException.php | 15 +++++ ...uctorWithoutParameterTypehintException.php | 15 +++++ 6 files changed, 162 insertions(+) create mode 100644 tests/Sniffs/Exceptions/data/ChainableConstructorException.php create mode 100644 tests/Sniffs/Exceptions/data/ConstructWithoutParametersException.php create mode 100644 tests/Sniffs/Exceptions/data/NonChainableConstructorException.php create mode 100644 tests/Sniffs/Exceptions/data/NonChainableConstructorWithoutParameterTypehintException.php diff --git a/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php b/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php index 2fa844d..708c56d 100644 --- a/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php +++ b/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php @@ -6,12 +6,15 @@ use PHP_CodeSniffer\Files\File as PhpCsFile; use SlevomatCodingStandard\Helpers\ClassHelper; +use SlevomatCodingStandard\Helpers\FunctionHelper; use SlevomatCodingStandard\Helpers\StringHelper; +use SlevomatCodingStandard\Helpers\TokenHelper; class ExceptionDeclarationSniff implements \PHP_CodeSniffer\Sniffs\Sniff { const CODE_NOT_ENDING_WITH_EXCEPTION = 'NotEndingWithException'; + const CODE_NOT_CHAINABLE = 'NotChainable'; /** * @return int[] @@ -40,6 +43,8 @@ public function process(PhpCsFile $phpcsFile, $classPointer) } $this->checkExceptionName($phpcsFile, $classPointer); + + $this->checkThatExceptionIsChainable($phpcsFile, $classPointer); } private function checkExceptionName(PhpCsFile $phpcsFile, int $classPointer) @@ -53,4 +58,58 @@ private function checkExceptionName(PhpCsFile $phpcsFile, int $classPointer) } } + private function checkThatExceptionIsChainable(PhpCsFile $phpcsFile, int $classPointer) + { + $constructorPointer = $this->findConstructorMethodPointer($phpcsFile, $classPointer); + if ($constructorPointer === null) { + return; + } + + $typeHints = FunctionHelper::getParametersTypeHints($phpcsFile, $constructorPointer); + if (count($typeHints) === 0) { + $phpcsFile->addError( + 'Exception is not chainable. It must have optional \Throwable as last constructor argument.', + $constructorPointer, + self::CODE_NOT_CHAINABLE + ); + return; + } + $lastArgument = array_pop($typeHints); + + if ($lastArgument === null) { + $phpcsFile->addError( + 'Exception is not chainable. It must have optional \Throwable as last constructor argument and has none.', + $constructorPointer, + self::CODE_NOT_CHAINABLE + ); + return; + } + + if ($lastArgument->getTypeHint() !== '\Throwable') { + $phpcsFile->addError(sprintf( + 'Exception is not chainable. It must have optional \Throwable as last constructor argument and has "%s".', + $lastArgument->getTypeHint() + ), $constructorPointer, self::CODE_NOT_CHAINABLE); + return; + } + } + + /** + * @param \PHP_CodeSniffer\Files\File $phpcsFile + * @param int $classPointer + * @return int|null + */ + private function findConstructorMethodPointer(PhpCsFile $phpcsFile, int $classPointer) + { + $functionPointerToScan = $classPointer; + while (($functionPointer = TokenHelper::findNext($phpcsFile, T_FUNCTION, $functionPointerToScan)) !== null) { + $functionName = FunctionHelper::getName($phpcsFile, $functionPointer); + if ($functionName === '__construct') { + return $functionPointer; + } + $functionPointerToScan = $functionPointer + 1; + } + return null; + } + } diff --git a/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php b/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php index 50b6e75..8038d73 100644 --- a/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php +++ b/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php @@ -99,4 +99,47 @@ public function testInterfaceThatExtendsExceptionIncorrectName() ); } + public function testExceptionWithConstructorWithoutParametersIsNotChainable() + { + $resultFile = $this->checkFile(__DIR__ . '/data/ConstructWithoutParametersException.php'); + + $this->assertSniffError( + $resultFile, + 10, + ExceptionDeclarationSniff::CODE_NOT_CHAINABLE, + 'Exception is not chainable. It must have optional \Throwable as last constructor argument.' + ); + } + + public function testExceptionWithChainableConstructorIsChainable() + { + $resultFile = $this->checkFile(__DIR__ . '/data/ChainableConstructorException.php'); + + $this->assertNoSniffError($resultFile, 10); + } + + public function testExceptionWithNonchainableConstructorIsNotChainable() + { + $resultFile = $this->checkFile(__DIR__ . '/data/NonChainableConstructorException.php'); + + $this->assertSniffError( + $resultFile, + 10, + ExceptionDeclarationSniff::CODE_NOT_CHAINABLE, + 'Exception is not chainable. It must have optional \Throwable as last constructor argument and has "string".' + ); + } + + public function testExceptionWithConstructorWithoutParameterTypeHintIsNotChainable() + { + $resultFile = $this->checkFile(__DIR__ . '/data/NonChainableConstructorWithoutParameterTypehintException.php'); + + $this->assertSniffError( + $resultFile, + 10, + ExceptionDeclarationSniff::CODE_NOT_CHAINABLE, + 'Exception is not chainable. It must have optional \Throwable as last constructor argument and has none.' + ); + } + } diff --git a/tests/Sniffs/Exceptions/data/ChainableConstructorException.php b/tests/Sniffs/Exceptions/data/ChainableConstructorException.php new file mode 100644 index 0000000..b5081fe --- /dev/null +++ b/tests/Sniffs/Exceptions/data/ChainableConstructorException.php @@ -0,0 +1,15 @@ + Date: Sun, 25 Jun 2017 18:49:56 +0200 Subject: [PATCH 3/3] Exceptions must be placed in configured directory --- .../Exceptions/ExceptionDeclarationSniff.php | 28 +++++ .../ExceptionDeclarationSniffTest.php | 110 +++++++++++++++--- tests/Sniffs/TestCase.php | 14 ++- 3 files changed, 136 insertions(+), 16 deletions(-) diff --git a/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php b/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php index 708c56d..68bc087 100644 --- a/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php +++ b/Consistence/Sniffs/Exceptions/ExceptionDeclarationSniff.php @@ -15,6 +15,10 @@ class ExceptionDeclarationSniff implements \PHP_CodeSniffer\Sniffs\Sniff const CODE_NOT_ENDING_WITH_EXCEPTION = 'NotEndingWithException'; const CODE_NOT_CHAINABLE = 'NotChainable'; + const CODE_INCORRECT_EXCEPTION_DIRECTORY = 'IncorrectExceptionDirectory'; + + /** @var string */ + public $exceptionsDirectoryName = 'exceptions'; /** * @return int[] @@ -44,6 +48,8 @@ public function process(PhpCsFile $phpcsFile, $classPointer) $this->checkExceptionName($phpcsFile, $classPointer); + $this->checkExceptionDirectoryName($phpcsFile, $classPointer); + $this->checkThatExceptionIsChainable($phpcsFile, $classPointer); } @@ -58,6 +64,28 @@ private function checkExceptionName(PhpCsFile $phpcsFile, int $classPointer) } } + private function checkExceptionDirectoryName(PhpCsFile $phpcsFile, int $classPointer) + { + $filename = $phpcsFile->getFilename(); + + // normalize path for Windows (PHP_CodeSniffer detects it with backslashes on Windows) + $filename = str_replace('\\', '/', $filename); + + $pathInfo = pathinfo($filename); + $pathSegments = explode('/', $pathInfo['dirname']); + + $exceptionDirectoryName = array_pop($pathSegments); + + if ($exceptionDirectoryName !== $this->exceptionsDirectoryName) { + $phpcsFile->addError(sprintf( + 'Exception file "%s" must be placed in "%s" directory (is in "%s").', + $pathInfo['basename'], + $this->exceptionsDirectoryName, + $exceptionDirectoryName + ), $classPointer, self::CODE_INCORRECT_EXCEPTION_DIRECTORY); + } + } + private function checkThatExceptionIsChainable(PhpCsFile $phpcsFile, int $classPointer) { $constructorPointer = $this->findConstructorMethodPointer($phpcsFile, $classPointer); diff --git a/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php b/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php index 8038d73..6bcc3d7 100644 --- a/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php +++ b/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php @@ -9,7 +9,9 @@ class ExceptionDeclarationSniffTest extends \Consistence\Sniffs\TestCase public function testInvalidExceptionName() { - $resultFile = $this->checkFile(__DIR__ . '/data/InvalidExceptionName.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/InvalidExceptionName.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertSniffError( $resultFile, @@ -21,28 +23,36 @@ public function testInvalidExceptionName() public function testValidClassName() { - $resultFile = $this->checkFile(__DIR__ . '/data/ValidNameException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/ValidNameException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertNoSniffError($resultFile, 7); } public function testValidClassNameThatExtendsCustomException() { - $resultFile = $this->checkFile(__DIR__ . '/data/ValidClassNameThatExtendsCustomException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/ValidClassNameThatExtendsCustomException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertNoSniffError($resultFile, 7); } public function testAbstractExceptionWithValidNameException() { - $resultFile = $this->checkFile(__DIR__ . '/data/AbstractExceptionWithValidNameException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/AbstractExceptionWithValidNameException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertNoSniffError($resultFile, 7); } public function testAbstractClassWithInvalidExceptionName() { - $resultFile = $this->checkFile(__DIR__ . '/data/AbstractExceptionWithInvalidName.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/AbstractExceptionWithInvalidName.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertSniffError( $resultFile, @@ -54,42 +64,54 @@ public function testAbstractClassWithInvalidExceptionName() public function testClassThatDoesNotExtendAnything() { - $resultFile = $this->checkFile(__DIR__ . '/data/ClassThatDoesNotExtendAnything.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/ClassThatDoesNotExtendAnything.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertNoSniffError($resultFile, 7); } public function testClassThatExtendsRegularClass() { - $resultFile = $this->checkFile(__DIR__ . '/data/ClassThatDoesNotExtendException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/ClassThatDoesNotExtendException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertNoSniffError($resultFile, 7); } public function testInterfaceThatDoesNotExtendAnything() { - $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatDoesNotExtendAnything.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatDoesNotExtendAnything.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertNoSniffError($resultFile, 7); } public function testInterfaceThatDoesNotExtendAnythingException() { - $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatDoesNotExtendAnythingException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatDoesNotExtendAnythingException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertNoSniffError($resultFile, 7); } public function testInterfaceThatExtendsException() { - $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatExtendsException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatExtendsException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertNoSniffError($resultFile, 7); } public function testInterfaceThatExtendsExceptionIncorrectName() { - $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatExtendsExceptionIncorrectName.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatExtendsExceptionIncorrectName.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertSniffError( $resultFile, @@ -101,7 +123,9 @@ public function testInterfaceThatExtendsExceptionIncorrectName() public function testExceptionWithConstructorWithoutParametersIsNotChainable() { - $resultFile = $this->checkFile(__DIR__ . '/data/ConstructWithoutParametersException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/ConstructWithoutParametersException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertSniffError( $resultFile, @@ -113,14 +137,18 @@ public function testExceptionWithConstructorWithoutParametersIsNotChainable() public function testExceptionWithChainableConstructorIsChainable() { - $resultFile = $this->checkFile(__DIR__ . '/data/ChainableConstructorException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/ChainableConstructorException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertNoSniffError($resultFile, 10); } public function testExceptionWithNonchainableConstructorIsNotChainable() { - $resultFile = $this->checkFile(__DIR__ . '/data/NonChainableConstructorException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/NonChainableConstructorException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertSniffError( $resultFile, @@ -132,7 +160,9 @@ public function testExceptionWithNonchainableConstructorIsNotChainable() public function testExceptionWithConstructorWithoutParameterTypeHintIsNotChainable() { - $resultFile = $this->checkFile(__DIR__ . '/data/NonChainableConstructorWithoutParameterTypehintException.php'); + $resultFile = $this->checkFile(__DIR__ . '/data/NonChainableConstructorWithoutParameterTypehintException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); $this->assertSniffError( $resultFile, @@ -142,4 +172,54 @@ public function testExceptionWithConstructorWithoutParameterTypeHintIsNotChainab ); } + public function testExceptionIsPlacedInCorrectDirectory() + { + $resultFile = $this->checkFile(__DIR__ . '/data/ValidNameException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); + + $this->assertNoSniffError($resultFile, 7); + } + + /** + * @requires OS WIN + */ + public function testExceptionIsPlacedInCorrectDirectoryOnWindows() + { + // PHP_CodeSniffer detects the path with backslashes on Windows + $resultFile = $this->checkFile(__DIR__ . '\data\ValidNameException.php', [ + 'exceptionsDirectoryName' => 'data', + ]); + + $this->assertNoSniffError($resultFile, 7); + } + + public function testExceptionIsPlacedInIncorrectDirectory() + { + $resultFile = $this->checkFile(__DIR__ . '/data/ValidNameException.php', [ + 'exceptionsDirectoryName' => 'exceptions', + ]); + + $this->assertSniffError( + $resultFile, + 7, + ExceptionDeclarationSniff::CODE_INCORRECT_EXCEPTION_DIRECTORY, + 'Exception file "ValidNameException.php" must be placed in "exceptions" directory (is in "data").' + ); + } + + public function testExceptionIsPlacedInIncorrectDirectoryCaseSensitively() + { + $resultFile = $this->checkFile(__DIR__ . '/data/ValidNameException.php', [ + 'exceptionsDirectoryName' => 'Data', + ]); + + $this->assertSniffError( + $resultFile, + 7, + ExceptionDeclarationSniff::CODE_INCORRECT_EXCEPTION_DIRECTORY, + 'Exception file "ValidNameException.php" must be placed in "Data" directory (is in "data").' + ); + } + } diff --git a/tests/Sniffs/TestCase.php b/tests/Sniffs/TestCase.php index 7558267..cd6510d 100644 --- a/tests/Sniffs/TestCase.php +++ b/tests/Sniffs/TestCase.php @@ -22,7 +22,15 @@ public function __construct(string $name = null, array $data = [], string $dataN parent::__construct($name, $data, $dataName); } - protected function checkFile(string $filePath): PhpCsFile + /** + * @param string $filePath + * @param mixed[] $sniffProperties + * @return \PHP_CodeSniffer\Files\File + */ + protected function checkFile( + string $filePath, + array $sniffProperties = [] + ): PhpCsFile { if (!is_readable($filePath)) { throw new \Exception(sprintf( @@ -38,6 +46,10 @@ protected function checkFile(string $filePath): PhpCsFile $codeSniffer->init(); + if (count($sniffProperties) > 0) { + $codeSniffer->ruleset->ruleset[$this->getSniffName()]['properties'] = $sniffProperties; + } + $codeSniffer->ruleset->sniffs = [$this->getSniffClassName() => $this->getSniffClassName()]; $codeSniffer->ruleset->populateTokenListeners();