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'
];