diff --git a/.travis.yml b/.travis.yml index ba3c0297..91e99462 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,8 @@ install: travis_retry composer update --prefer-dist script: - vendor/bin/phpcs - vendor/bin/phpcs $(find tests/input/* | sort) --report=summary --report-file=phpcs.log; diff tests/expected_report.txt phpcs.log + - vendor/bin/phpstan analyse + - vendor/bin/phpunit stages: - Validate against schema diff --git a/composer.json b/composer.json index 3f913f0b..ba128cd2 100644 --- a/composer.json +++ b/composer.json @@ -38,5 +38,17 @@ "branch-alias": { "dev-master": "7.0.x-dev" } + }, + "require-dev": { + "phpunit/phpunit": "^7.5", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-deprecation-rules": "^0.11", + "phpstan/phpstan-strict-rules": "^0.11" + }, + "autoload-dev": { + "psr-4": { + "Doctrine\\": "tests/Doctrine" + } } } diff --git a/docs/en/reference/index.rst b/docs/en/reference/index.rst index e3fd44db..61374a1b 100644 --- a/docs/en/reference/index.rst +++ b/docs/en/reference/index.rst @@ -132,3 +132,15 @@ need to execute PHP_CodeSniffer with the tests folder and ensure it matches the .. code-block:: bash $ ./vendor/bin/phpcs tests/input --report=summary --report-file=phpcs.log; diff tests/expected_report.txt phpcs.log + +If you have implemented custom sniff also run PHPStan and PHPUnit. +The PHPUnit version to be used is the one installed as a dev- dependency +via composer (same rules are for PHPStan): + +.. code-block:: console + + $ ./vendor/bin/phpunit + $ ./vendor/bin/phpstan analyse + +Accepted coverage for new contributions is 80%. There must not be any errors shown by PHPStan. +Any contribution not satisfying this requirement won’t be merged. \ No newline at end of file diff --git a/lib/Doctrine/Sniffs/Arrays/OperatorSpacingAfterSniff.php b/lib/Doctrine/Sniffs/Arrays/OperatorSpacingAfterSniff.php new file mode 100644 index 00000000..3a6e74b3 --- /dev/null +++ b/lib/Doctrine/Sniffs/Arrays/OperatorSpacingAfterSniff.php @@ -0,0 +1,101 @@ +isOperator($phpcsFile, $pointer)) { + return; + } + + $this->ensureOneSpaceAfterOperator($phpcsFile, $pointer, $phpcsFile->getTokens()); + } + + /** + * @param mixed[] $tokens + */ + private function ensureOneSpaceAfterOperator(File $file, int $pointer, array $tokens) : void + { + if (! $this->shouldValidateAfter($pointer, $tokens)) { + return; + } + + $numberOfSpaces = $this->numberOfSpaces($tokens[$pointer + 1]); + + if ($numberOfSpaces === 1 || ! $this->recordErrorAfter($file, $pointer, $tokens[$pointer], $numberOfSpaces)) { + return; + } + + if ($numberOfSpaces === 0) { + $file->fixer->addContent($pointer, ' '); + + return; + } + + $file->fixer->replaceToken($pointer + 1, ' '); + } + + /** + * @param mixed[] $tokens + */ + private function shouldValidateAfter(int $pointer, array $tokens) : bool + { + if (! isset($tokens[$pointer + 1])) { + return false; + } + + return $tokens[$pointer]['code'] !== T_INLINE_THEN || $tokens[$pointer + 1]['code'] !== T_INLINE_ELSE; + } + + /** + * @param mixed[] $token + */ + private function recordErrorAfter(File $file, int $pointer, array $token, int $numberOfSpaces) : bool + { + return $file->addFixableError( + self::MESSAGE_AFTER, + $pointer, + 'NoSpaceAfterAssigment', + [$token['content'], $numberOfSpaces] + ); + } + + /** + * @param mixed[] $token + */ + private function numberOfSpaces(array $token) : int + { + if ($token['code'] !== T_WHITESPACE) { + return 0; + } + + return strlen($token['content']); + } +} diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 95aa891a..f603d4b6 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -15,5 +15,8 @@ - lib + lib/ + tests/Doctrine/ + + tests/**/data/* diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 00000000..0ac8caf0 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,17 @@ +parameters: + level: 7 + paths: + - "%currentWorkingDirectory%/lib/" + - "%currentWorkingDirectory%/tests/Doctrine" + autoload_files: + - "%currentWorkingDirectory%/tests/bootstrap.php" + ignoreErrors: + - + message: '#Method [a-zA-Z0-9\\_]+::process\(\) has parameter \$pointer with no typehint specified#' + path: %currentWorkingDirectory%/lib/Doctrine/Sniffs/* + +includes: + - vendor/phpstan/phpstan-deprecation-rules/rules.neon + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon + - vendor/phpstan/phpstan-strict-rules/rules.neon diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..0d122bde --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,15 @@ + + + + + tests/Doctrine/ + + diff --git a/tests/Doctrine/Sniffs/Arrays/OperatorSpacingAfterSniffTest.php b/tests/Doctrine/Sniffs/Arrays/OperatorSpacingAfterSniffTest.php new file mode 100644 index 00000000..e1a62385 --- /dev/null +++ b/tests/Doctrine/Sniffs/Arrays/OperatorSpacingAfterSniffTest.php @@ -0,0 +1,25 @@ +getErrorCount()); + + self::assertSniffError($phpcsFile, 4, 'NoSpaceAfterAssigment'); + } +} diff --git a/tests/Doctrine/Sniffs/Arrays/data/operatorSpacingAfterSniff.errors.php b/tests/Doctrine/Sniffs/Arrays/data/operatorSpacingAfterSniff.errors.php new file mode 100644 index 00000000..d1be2402 --- /dev/null +++ b/tests/Doctrine/Sniffs/Arrays/data/operatorSpacingAfterSniff.errors.php @@ -0,0 +1,11 @@ + 'value', 'key2' => 'value', ]; diff --git a/tests/input/array_indentation.php b/tests/input/array_indentation.php index fa6e10ab..8a9bfedc 100644 --- a/tests/input/array_indentation.php +++ b/tests/input/array_indentation.php @@ -22,3 +22,12 @@ 9, ], ]; + +$arrayWithMultipleSpacesAfterAssigmentOperator = [ + 0, + 1, + 2, + 3, + 4, + 5, +]; diff --git a/tests/input/trailing_comma_on_array.php b/tests/input/trailing_comma_on_array.php index aeb1a729..3b39e357 100644 --- a/tests/input/trailing_comma_on_array.php +++ b/tests/input/trailing_comma_on_array.php @@ -2,7 +2,7 @@ declare(strict_types=1); -$array = [ +$array = [ 'key1' => 'value', 'key2' => 'value' ];