* Dariusz Rumiński * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace PhpCsFixer\Tests\Fixer\ClassNotation; use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException; use PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer; use PhpCsFixer\Tests\Test\AbstractFixerTestCase; use PhpCsFixer\Tokenizer\Tokens; use PhpCsFixer\WhitespacesFixerConfig; /** * @internal * * @covers \PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer * * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer> * * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer */ final class ClassAttributesSeparationFixerTest extends AbstractFixerTestCase { /** * @param _AutogeneratedInputConfiguration $configuration * * @dataProvider provideFixCases */ public function testFix(string $expected, ?string $input = null, array $configuration = []): void { $this->fixer->configure($configuration); $this->doTest($expected, $input); } public static function provideFixCases(): iterable { yield [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ 'filter( function (\SplFileInfo $file) use ($files) { return !in_array($file->getRelativePathname(), $files, true); } ); } } private $a; public static function method145() { } abstract protected function method245(); // comment final private function method345() { } } function some1(){ echo 1;} function some2(){ echo 2;}', 'filter( function (\SplFileInfo $file) use ($files) { return !in_array($file->getRelativePathname(), $files, true); } ); } } private $a; public static function method145() { } abstract protected function method245(); // comment final private function method345() { } } function some1(){ echo 1;} function some2(){ echo 2;}', ]; yield [ ' * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace PhpCsFixer\Linter; /** * Dummy linter. No linting is performed. No error is raised. * * @author Dariusz Rumiński * * @internal */ final class NullLinter implements LinterInterface { /** * {@inheritdoc} */ public function lintFile($path) { unset($path); } /** * {@inheritdoc} */ public function lintSource($source) { unset($source); } } ', ]; // do not touch anonymous functions (since PHP doesn't allow // for class attributes being functions :(, we only have to test // those used within methods) yield [ ' [ ' true, 2 => false, ]; // comment2 private $bar = 1; }', ' true, 2 => false, ]; // comment2 private $bar = 1; }', ['elements' => ['property' => 'one']], ]; yield 'trait group import none' => [ ' ['trait_import' => 'none']], ]; yield [ ' ['property' => 'none']], ]; yield [ ' ['const' => 'none']], ]; yield 'multiple trait import 5954' => [ ' ['method' => 'one']], ]; yield 'multiple trait import with method 5954' => [ ' ['method' => 'one']], ]; yield 'trait group import 5843' => [ ' ['method' => 'one', 'trait_import' => 'one']], ]; yield [ ' ['method' => 'one', 'trait_import' => 'one']], ]; yield 'trait group import 5852' => [ ' ['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'none']], ]; yield [ ' ['const' => 'one', 'method' => 'one', 'property' => 'one']], ]; yield [ ' ['property' => 'one']], ]; yield [ ' ['property' => 'none']], ]; yield [ ' ['const' => 'one']], ]; yield [ ' ['const' => 'none']], ]; yield [ ' ['method' => 'one']], ]; yield [ ' ['method' => 'none']], ]; yield [ ' ['property' => 'none', 'method' => 'one']], ]; yield [ ' ['const' => 'none', 'method' => 'one']], ]; yield [ ' ['const' => 'none', 'method' => 'one']], ]; yield [ ' ['const' => 'only_if_meta']], ]; yield [ ' ['property' => 'only_if_meta']], ]; yield [ ' ['method' => 'only_if_meta']], ]; yield [ ' ['const' => 'only_if_meta', 'property' => 'only_if_meta', 'method' => 'only_if_meta']], ]; yield [ ' ['property' => 'none', 'trait_import' => 'none']], ]; yield [ ' ['property' => 'only_if_meta']], ]; yield [ 'fixer->configure($config); $this->doTest($expected, $input); } public static function provideFix80Cases(): iterable { yield 'attributes' => [ ' "The email {{ value }} is not a valid email."])] private $email; #[Assert\String()] private $name; }', ' "The email {{ value }} is not a valid email."])] private $email; #[Assert\String()] private $name; }', ]; yield 'attributes minimal' => [ ' [ ' "Foo"])] private $email; }', ' "Foo"])] private $email; }', ]; yield 'constructor property promotion' => [ ' [ ' [ ' ['property' => 'only_if_meta']], ]; yield 'mixed attributes and phpdoc with conditional spacing' => [ ' "Foo"])] private $email; #[Assert\String()] #[ORM\Column()] private $place; #[ORM\Column()] /** @var string */ private $hash; /** @var string **/ #[ORM\Column()] /** @internal */ private $updatedAt; } ', ' "Foo"])] private $email; #[Assert\String()] #[ORM\Column()] private $place; #[ORM\Column()] /** @var string */ private $hash; /** @var string **/ #[ORM\Column()] /** @internal */ private $updatedAt; } ', ['elements' => ['property' => 'only_if_meta']], ]; yield [ ' "Foo"])] private $email; private $foo1; #1 private $foo2; /* @2 */ }', ' "Foo"])] private $email; private $foo1; #1 private $foo2; /* @2 */ }', ['elements' => ['property' => 'none']], ]; } /** * @param _AutogeneratedInputConfiguration $config * * @dataProvider provideFix81Cases * * @requires PHP 8.1 */ public function testFix81(string $expected, ?string $input, array $config = []): void { $this->fixer->configure($config); $this->doTest($expected, $input); } public static function provideFix81Cases(): iterable { yield [ ' [ ' [ 'const' => 'one', 'method' => 'one', 'case' => 'one', ]], ]; yield [ ' [ 'const' => 'none', 'method' => 'one', 'case' => 'none', ]], ]; } /** * @dataProvider provideFix82Cases * * @requires PHP 8.2 */ public function testFix82(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } /** * @return iterable */ public static function provideFix82Cases(): iterable { yield [ 'fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } /** * @return iterable */ public static function provideWithWhitespacesConfigCases(): iterable { yield [ " $elements * * @dataProvider provideInvalidConfigurationCases */ public function testInvalidConfiguration(array $elements): void { $this->expectException(InvalidFixerConfigurationException::class); $this->fixer->configure(['elements' => $elements]); } public static function provideInvalidConfigurationCases(): iterable { yield 'numeric keys' => [['method', 'property']]; yield 'wrong key name' => [['methods' => 'one']]; yield 'wrong key value' => [['method' => 'two']]; } /** * @dataProvider provideCommentBlockStartDetectionCases */ public function testCommentBlockStartDetection(int $expected, string $code, int $index): void { Tokens::clearCache(); $tokens = Tokens::fromCode($code); $result = \Closure::bind(static fn (ClassAttributesSeparationFixer $fixer): int => $fixer->findCommentBlockStart($tokens, $index, 0), null, ClassAttributesSeparationFixer::class)($this->fixer); self::assertSame( $expected, $result, \sprintf('Expected index %d (%s) got index %d (%s).', $expected, $tokens[$expected]->toJson(), $result, $tokens[$result]->toJson()) ); } /** * @return iterable */ public static function provideCommentBlockStartDetectionCases(): iterable { yield [ 4, '