From 8175e4b55eff5a865731b72ced3c5ba546040728 Mon Sep 17 00:00:00 2001 From: Petr Duda Date: Thu, 9 Mar 2023 09:54:57 +0100 Subject: [PATCH 1/2] stop calling static methods in tests as non-static --- tests/Sniffs/TestCase.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/Sniffs/TestCase.php b/tests/Sniffs/TestCase.php index 7be4389..a53d279 100644 --- a/tests/Sniffs/TestCase.php +++ b/tests/Sniffs/TestCase.php @@ -4,6 +4,7 @@ namespace Consistence\Sniffs; +use PHPUnit\Framework\Assert; use PHP_CodeSniffer\Config as PhpCsConfig; use PHP_CodeSniffer\Files\File as PhpCsFile; use PHP_CodeSniffer\Files\LocalFile as PhpCsLocalFile; @@ -84,12 +85,12 @@ protected function getSniffClassName(): string protected function assertSniffError(PhpCsFile $resultFile, int $line, string $code, ?string $message = null): void { $errors = $resultFile->getErrors(); - $this->assertTrue( + Assert::assertTrue( isset($errors[$line]), sprintf('Expected error on line %s, but none occurred', $line) ); $expectedCode = $this->getSniffName() . '.' . $code; - $this->assertTrue( + Assert::assertTrue( $this->hasError($errors[$line], $expectedCode, $message), sprintf( 'Expected code %s%s, but not found on line %s.%sErrors found on this line:%s%s%s', @@ -129,7 +130,7 @@ private function hasError(iterable $errorsForLine, string $code, ?string $messag protected function assertNoSniffError(PhpCsFile $resultFile, int $line): void { $errors = $resultFile->getErrors(); - $this->assertFalse( + Assert::assertFalse( isset($errors[$line]), sprintf( 'Expected no error on line %s, but errors found:%s%s%s', @@ -145,7 +146,7 @@ protected function assertNoSniffErrorInFile(PhpCsFile $file): void { $errorsForFile = $file->getErrors(); - $this->assertEmpty($errorsForFile, sprintf( + Assert::assertEmpty($errorsForFile, sprintf( 'No errors expected, but %d errors found: %s%s%s%s', count($errorsForFile), PHP_EOL, From ad91abef25d6d4e16276f46a48395cbf12eb9cf1 Mon Sep 17 00:00:00 2001 From: Petr Duda Date: Thu, 9 Mar 2023 10:23:54 +0100 Subject: [PATCH 2/2] deduplicate test methods using data providers --- .../ExceptionDeclarationSniffTest.php | 333 +++++++----------- .../ValidVariableNameSniffTest.php | 69 +++- 2 files changed, 188 insertions(+), 214 deletions(-) diff --git a/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php b/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php index fbfb2ce..fb783ef 100644 --- a/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php +++ b/tests/Sniffs/Exceptions/ExceptionDeclarationSniffTest.php @@ -4,201 +4,160 @@ namespace Consistence\Sniffs\Exceptions; +use Generator; + class ExceptionDeclarationSniffTest extends \Consistence\Sniffs\TestCase { - public function testInvalidExceptionName(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/InvalidExceptionName.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertSniffError( - $resultFile, - 7, - ExceptionDeclarationSniff::CODE_NOT_ENDING_WITH_EXCEPTION, - 'Exception class name "InvalidExceptionName" must end with "Exception".' - ); - } - - public function testValidClassName(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/ValidNameException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - - public function testValidClassNameThatExtendsCustomException(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/ValidClassNameThatExtendsCustomException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - - public function testAbstractExceptionWithValidNameException(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/AbstractExceptionWithValidNameException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - - public function testAbstractClassWithInvalidExceptionName(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/AbstractExceptionWithInvalidName.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertSniffError( - $resultFile, - 7, - ExceptionDeclarationSniff::CODE_NOT_ENDING_WITH_EXCEPTION, - 'Exception class name "AbstractExceptionWithInvalidName" must end with "Exception".' - ); - } - - public function testClassThatDoesNotExtendAnything(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/ClassThatDoesNotExtendAnything.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - - public function testClassThatExtendsRegularClass(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/ClassThatDoesNotExtendException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - - public function testInterfaceThatDoesNotExtendAnything(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatDoesNotExtendAnything.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - - public function testInterfaceThatDoesNotExtendAnythingException(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatDoesNotExtendAnythingException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - - public function testInterfaceThatExtendsException(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatExtendsException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - - public function testInterfaceThatExtendsExceptionIncorrectName(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/InterfaceThatExtendsExceptionIncorrectName.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertSniffError( - $resultFile, - 7, - ExceptionDeclarationSniff::CODE_NOT_ENDING_WITH_EXCEPTION, - 'Exception class name "InterfaceThatExtendsExceptionIncorrectName" must end with "Exception".' - ); - } - - public function testExceptionWithConstructorWithoutParametersIsNotChainable(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/ConstructWithoutParametersException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertSniffError( - $resultFile, - 10, - ExceptionDeclarationSniff::CODE_NOT_CHAINABLE, - 'Exception is not chainable. It must have optional \Throwable as last constructor argument.' - ); - } - - public function testExceptionWithChainableConstructorIsChainable(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/ChainableConstructorException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - - public function testExceptionWithCustomExceptionArgumentIsChainable(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/CustomExceptionArgumentChainableConstructorException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); + /** + * @return mixed[][]|\Generator + */ + public function validExceptionDeclarationDataProvider(): Generator + { + yield 'valid class name' => [ + 'filePath' => __DIR__ . '/data/ValidNameException.php', + ]; + yield 'valid class name that extends custom exception' => [ + 'filePath' => __DIR__ . '/data/ValidClassNameThatExtendsCustomException.php', + ]; + yield 'abstract exception with valid name' => [ + 'filePath' => __DIR__ . '/data/AbstractExceptionWithValidNameException.php', + ]; + yield 'class that does not extend anything' => [ + 'filePath' => __DIR__ . '/data/ClassThatDoesNotExtendAnything.php', + ]; + yield 'class that extends regular class' => [ + 'filePath' => __DIR__ . '/data/ClassThatDoesNotExtendException.php', + ]; + yield 'interface that does not extend anything' => [ + 'filePath' => __DIR__ . '/data/InterfaceThatDoesNotExtendAnything.php', + ]; + yield 'interface that does not extend anything exception' => [ + 'filePath' => __DIR__ . '/data/InterfaceThatDoesNotExtendAnythingException.php', + ]; + yield 'interface that extends exception' => [ + 'filePath' => __DIR__ . '/data/InterfaceThatExtendsException.php', + ]; + yield 'exception with chainable constructor is chainable' => [ + 'filePath' => __DIR__ . '/data/ChainableConstructorException.php', + ]; + yield 'exception with custom exception argument is chainable' => [ + 'filePath' => __DIR__ . '/data/CustomExceptionArgumentChainableConstructorException.php', + ]; + yield 'exception with error argument is chainable' => [ + 'filePath' => __DIR__ . '/data/ErrorArgumentChainableConstructorException.php', + ]; + yield 'exception is placed in correct directory' => [ + 'filePath' => __DIR__ . '/data/ValidNameException.php', + ]; } - public function testExceptionWithErrorArgumentIsChainable(): void + /** + * @dataProvider validExceptionDeclarationDataProvider + * + * @param string $filePath + */ + public function testValidExceptionDeclaration(string $filePath): void { - $resultFile = $this->checkFile(__DIR__ . '/data/ErrorArgumentChainableConstructorException.php', [ + $resultFile = $this->checkFile($filePath, [ 'exceptionsDirectoryName' => 'data', ]); $this->assertNoSniffErrorInFile($resultFile); } - public function testExceptionWithNonchainableConstructorIsNotChainable(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/NonChainableConstructorException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertSniffError( - $resultFile, - 10, - ExceptionDeclarationSniff::CODE_NOT_CHAINABLE, - 'Exception is not chainable. It must have optional \Throwable as last constructor argument and has "string".' - ); + /** + * @return mixed[][]|\Generator + */ + public function invalidExceptionDeclarationDataProvider(): Generator + { + yield 'invalid exception name' => [ + 'filePath' => __DIR__ . '/data/InvalidExceptionName.php', + 'exceptionsDirectoryName' => 'data', + 'line' => 7, + 'code' => ExceptionDeclarationSniff::CODE_NOT_ENDING_WITH_EXCEPTION, + 'message' => 'Exception class name "InvalidExceptionName" must end with "Exception".', + ]; + yield 'abstract class with invalid exception name' => [ + 'filePath' => __DIR__ . '/data/AbstractExceptionWithInvalidName.php', + 'exceptionsDirectoryName' => 'data', + 'line' => 7, + 'code' => ExceptionDeclarationSniff::CODE_NOT_ENDING_WITH_EXCEPTION, + 'message' => 'Exception class name "AbstractExceptionWithInvalidName" must end with "Exception".', + ]; + yield 'interface that extends exception incorrect name' => [ + 'filePath' => __DIR__ . '/data/InterfaceThatExtendsExceptionIncorrectName.php', + 'exceptionsDirectoryName' => 'data', + 'line' => 7, + 'code' => ExceptionDeclarationSniff::CODE_NOT_ENDING_WITH_EXCEPTION, + 'message' => 'Exception class name "InterfaceThatExtendsExceptionIncorrectName" must end with "Exception".', + ]; + yield 'exception with constructor without parameters is not chainable' => [ + 'filePath' => __DIR__ . '/data/ConstructWithoutParametersException.php', + 'exceptionsDirectoryName' => 'data', + 'line' => 10, + 'code' => ExceptionDeclarationSniff::CODE_NOT_CHAINABLE, + 'message' => 'Exception is not chainable. It must have optional \Throwable as last constructor argument.', + ]; + yield 'exception with non-chainable constructor is not chainable' => [ + 'filePath' => __DIR__ . '/data/NonChainableConstructorException.php', + 'exceptionsDirectoryName' => 'data', + 'line' => 10, + 'code' => ExceptionDeclarationSniff::CODE_NOT_CHAINABLE, + 'message' => 'Exception is not chainable. It must have optional \Throwable as last constructor argument and has "string".', + ]; + yield 'exception with constructor without parameter type hint is not chainable' => [ + 'filePath' => __DIR__ . '/data/NonChainableConstructorWithoutParameterTypehintException.php', + 'exceptionsDirectoryName' => 'data', + 'line' => 10, + 'code' => ExceptionDeclarationSniff::CODE_NOT_CHAINABLE, + 'message' => 'Exception is not chainable. It must have optional \Throwable as last constructor argument and has none.', + ]; + yield 'exception is placed in incorrect directory' => [ + 'filePath' => __DIR__ . '/data/ValidNameException.php', + 'exceptionsDirectoryName' => 'exceptions', + 'line' => 7, + 'code' => ExceptionDeclarationSniff::CODE_INCORRECT_EXCEPTION_DIRECTORY, + 'message' => 'Exception file "ValidNameException.php" must be placed in "exceptions" directory (is in "data").', + ]; + yield 'exception is placed in incorrect directory case sensitively' => [ + 'filePath' => __DIR__ . '/data/ValidNameException.php', + 'exceptionsDirectoryName' => 'Data', + 'line' => 7, + 'code' => ExceptionDeclarationSniff::CODE_INCORRECT_EXCEPTION_DIRECTORY, + 'message' => 'Exception file "ValidNameException.php" must be placed in "Data" directory (is in "data").', + ]; } - public function testExceptionWithConstructorWithoutParameterTypeHintIsNotChainable(): void + /** + * @dataProvider invalidExceptionDeclarationDataProvider + * + * @param string $filePath + * @param string $exceptionsDirectoryName + * @param int $line + * @param string $code + * @param string $message + */ + public function testInvalidExceptionDeclaration( + string $filePath, + string $exceptionsDirectoryName, + int $line, + string $code, + string $message + ): void { - $resultFile = $this->checkFile(__DIR__ . '/data/NonChainableConstructorWithoutParameterTypehintException.php', [ - 'exceptionsDirectoryName' => 'data', + $resultFile = $this->checkFile($filePath, [ + 'exceptionsDirectoryName' => $exceptionsDirectoryName, ]); $this->assertSniffError( $resultFile, - 10, - ExceptionDeclarationSniff::CODE_NOT_CHAINABLE, - 'Exception is not chainable. It must have optional \Throwable as last constructor argument and has none.' + $line, + $code, + $message ); } - public function testExceptionIsPlacedInCorrectDirectory(): void - { - $resultFile = $this->checkFile(__DIR__ . '/data/ValidNameException.php', [ - 'exceptionsDirectoryName' => 'data', - ]); - - $this->assertNoSniffErrorInFile($resultFile); - } - /** * @requires OS WIN */ @@ -212,32 +171,4 @@ public function testExceptionIsPlacedInCorrectDirectoryOnWindows(): void $this->assertNoSniffErrorInFile($resultFile); } - public function testExceptionIsPlacedInIncorrectDirectory(): void - { - $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(): void - { - $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/NamingConventions/ValidVariableNameSniffTest.php b/tests/Sniffs/NamingConventions/ValidVariableNameSniffTest.php index ed09422..ea1274c 100644 --- a/tests/Sniffs/NamingConventions/ValidVariableNameSniffTest.php +++ b/tests/Sniffs/NamingConventions/ValidVariableNameSniffTest.php @@ -4,6 +4,7 @@ namespace Consistence\Sniffs\NamingConventions; +use Generator; use PHP_CodeSniffer\Files\File as PhpCsFile; class ValidVariableNameSniffTest extends \Consistence\Sniffs\TestCase @@ -14,29 +15,71 @@ private function getFileReport(): PhpCsFile return $this->checkFile(__DIR__ . '/data/FooClass.php'); } - public function testValidVariable(): void + /** + * @return mixed[][]|\Generator + */ + public function validVariableNameDataProvider(): Generator { - $this->assertNoSniffError($this->getFileReport(), 12); + yield 'variable' => [ + 'line' => 12, + ]; + yield 'variable on object' => [ + 'line' => 14, + ]; + yield 'variable on class' => [ + 'line' => 15, + ]; + yield 'PHP reserved variable' => [ + 'line' => 16, + ]; } - public function testNotCamelCaps(): void + /** + * @dataProvider validVariableNameDataProvider + * + * @param int $line + */ + public function testValidVariableName( + int $line + ): void { - $this->assertSniffError($this->getFileReport(), 13, ValidVariableNameSniff::CODE_CAMEL_CAPS, 'incorrect_variable'); + $this->assertNoSniffError( + $this->getFileReport(), + $line + ); } - public function testVariableOnObject(): void + /** + * @return mixed[][]|\Generator + */ + public function invalidVariableNameDataProvider(): Generator { - $this->assertNoSniffError($this->getFileReport(), 14); + yield 'not camel caps' => [ + 'line' => 13, + 'code' => ValidVariableNameSniff::CODE_CAMEL_CAPS, + 'message' => 'incorrect_variable', + ]; } - public function testVariableOnClass(): void + /** + * @dataProvider invalidVariableNameDataProvider + * + * @param int $line + * @param string $code + * @param string $message + */ + public function testInvalidVariableName( + int $line, + string $code, + string $message + ): void { - $this->assertNoSniffError($this->getFileReport(), 15); - } - - public function testPhpReservedVariables(): void - { - $this->assertNoSniffError($this->getFileReport(), 16); + $this->assertSniffError( + $this->getFileReport(), + $line, + $code, + $message + ); } }