* 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\Tokenizer\Analyzer; use PhpCsFixer\Tests\TestCase; use PhpCsFixer\Tokenizer\Analyzer\Analysis\AttributeAnalysis; use PhpCsFixer\Tokenizer\Analyzer\AttributeAnalyzer; use PhpCsFixer\Tokenizer\CT; use PhpCsFixer\Tokenizer\Tokens; /** * @internal * * @covers \PhpCsFixer\Tokenizer\Analyzer\AttributeAnalyzer */ final class AttributeAnalyzerTest extends TestCase { /** * Check it's not crashing for PHP lower than 8.0 as other tests run for PHP 8.0 only. */ public function testNotAnAttribute(): void { $tokens = Tokens::fromCode(' $token) { self::assertFalse(AttributeAnalyzer::isAttribute($tokens, $index)); } } /** * @requires PHP 8.0 * * @dataProvider provideIsAttributeCases */ public function testIsAttribute(bool $isInAttribute, string $code): void { $tokens = Tokens::fromCode($code); foreach ($tokens as $index => $token) { if ($token->equals([T_STRING, 'Foo'])) { if (isset($testedIndex)) { self::fail('Test is run against index of "Foo", multiple occurrences found.'); } $testedIndex = $index; } } if (!isset($testedIndex)) { self::fail('Test is run against index of "Foo", but it was not found in the code.'); } self::assertSame($isInAttribute, AttributeAnalyzer::isAttribute($tokens, $testedIndex)); } /** * Test case requires to having "Foo" as it will be searched for to test its index. * * @return iterable */ public static function provideIsAttributeCases(): iterable { yield [false, ' $expectedAnalyses */ public function testGetAttributeDeclarations(string $code, int $startIndex, array $expectedAnalyses): void { $tokens = Tokens::fromCode($code); $actualAnalyses = AttributeAnalyzer::collect($tokens, $startIndex); foreach ($expectedAnalyses as $expectedAnalysis) { self::assertSame(T_ATTRIBUTE, $tokens[$expectedAnalysis->getOpeningBracketIndex()]->getId()); self::assertSame(CT::T_ATTRIBUTE_CLOSE, $tokens[$expectedAnalysis->getClosingBracketIndex()]->getId()); } self::assertSame( serialize($expectedAnalyses), serialize($actualAnalyses), ); } /** * @return iterable}> */ public static function provideGetAttributeDeclarationsCases(): iterable { yield 'multiple #[] in a multiline group' => [ ' 5, 'end' => 13, 'name' => 'AB\Baz', ]]), new AttributeAnalysis(16, 49, 16, 48, [[ 'start' => 17, 'end' => 47, 'name' => 'A\B\Quux', ]]), new AttributeAnalysis(50, 60, 50, 59, [[ 'start' => 51, 'end' => 58, 'name' => '\A\B\Qux', ]]), new AttributeAnalysis(61, 67, 61, 66, [[ 'start' => 62, 'end' => 65, 'name' => 'BarAlias', ]]), new AttributeAnalysis(68, 73, 70, 72, [[ 'start' => 71, 'end' => 71, 'name' => 'Corge', ]]), new AttributeAnalysis(74, 83, 74, 82, [[ 'start' => 75, 'end' => 81, 'name' => 'Foo', ]]), ], ]; yield 'multiple #[] in a single line group' => [ ' 4, 'end' => 12, 'name' => 'AB\Baz', ]]), new AttributeAnalysis(15, 48, 15, 47, [[ 'start' => 16, 'end' => 46, 'name' => 'A\B\Quux', ]]), new AttributeAnalysis(49, 59, 49, 58, [[ 'start' => 50, 'end' => 57, 'name' => '\A\B\Qux', ]]), new AttributeAnalysis(60, 66, 60, 65, [[ 'start' => 61, 'end' => 64, 'name' => 'BarAlias', ]]), new AttributeAnalysis(67, 71, 68, 70, [[ 'start' => 69, 'end' => 69, 'name' => 'Corge', ]]), new AttributeAnalysis(72, 80, 72, 80, [[ 'start' => 73, 'end' => 79, 'name' => 'Foo', ]]), ], ]; yield 'comma-separated attributes in a multiline #[]' => [ ' 3, 'end' => 14, 'name' => 'AB\Baz', ], [ 'start' => 16, 'end' => 47, 'name' => 'A\B\Quux', ], [ 'start' => 49, 'end' => 57, 'name' => '\A\B\Qux', ], [ 'start' => 59, 'end' => 63, 'name' => 'BarAlias', ], [ 'start' => 65, 'end' => 68, 'name' => 'Corge', ], [ 'start' => 70, 'end' => 79, 'name' => 'Foo', ]]), ], ]; yield 'comma-separated attributes in a single line #[]' => [ ' 3, 'end' => 12, 'name' => 'AB\Baz', ], [ 'start' => 14, 'end' => 45, 'name' => 'A\B\Quux', ], [ 'start' => 47, 'end' => 55, 'name' => '\A\B\Qux', ], [ 'start' => 57, 'end' => 61, 'name' => 'BarAlias', ], [ 'start' => 63, 'end' => 65, 'name' => 'Corge', ], [ 'start' => 67, 'end' => 75, 'name' => 'Foo', ]]), ], ]; } /** * @requires PHP 8.1 * * @dataProvider provideGetAttributeDeclarations81Cases * * @param list $expectedAnalyses */ public function testGetAttributeDeclarations81(string $code, int $startIndex, array $expectedAnalyses): void { $this->testGetAttributeDeclarations($code, $startIndex, $expectedAnalyses); } /** * @return iterable}> */ public static function provideGetAttributeDeclarations81Cases(): iterable { yield 'multiple #[] in a group, including `new` in arguments' => [ ' 3, 'end' => 11, 'name' => 'AB\Baz', ]]), new AttributeAnalysis(14, 34, 14, 33, [[ 'start' => 15, 'end' => 32, 'name' => '\A\B\Qux', ]]), new AttributeAnalysis(35, 38, 35, 37, [[ 'start' => 36, 'end' => 36, 'name' => 'Corge', ]]), ], ]; yield 'comma-separated attributes in single #[] group, including `new` in arguments' => [ ' 3, 'end' => 12, 'name' => 'AB\Baz', ], [ 'start' => 14, 'end' => 32, 'name' => '\A\B\Qux', ], [ 'start' => 34, 'end' => 35, 'name' => 'Corge', ]]), ], ]; } }