* 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\Transformer; use PhpCsFixer\Tests\Test\AbstractTransformerTestCase; use PhpCsFixer\Tokenizer\CT; use PhpCsFixer\Tokenizer\Tokens; /** * @author Dariusz Rumiński * * @internal * * @covers \PhpCsFixer\Tokenizer\Transformer\BraceTransformer * * @phpstan-import-type _TransformerTestExpectedTokens from AbstractTransformerTestCase */ final class BraceTransformerTest extends AbstractTransformerTestCase { /** * @param _TransformerTestExpectedTokens $expectedTokens * * @dataProvider provideProcessCases */ public function testProcess(string $source, array $expectedTokens = []): void { $this->doTest( $source, $expectedTokens, [ T_CURLY_OPEN, CT::T_CURLY_CLOSE, T_DOLLAR_OPEN_CURLY_BRACES, CT::T_DOLLAR_CLOSE_CURLY_BRACES, CT::T_DYNAMIC_PROP_BRACE_OPEN, CT::T_DYNAMIC_PROP_BRACE_CLOSE, CT::T_DYNAMIC_VAR_BRACE_OPEN, CT::T_DYNAMIC_VAR_BRACE_CLOSE, CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, CT::T_GROUP_IMPORT_BRACE_OPEN, CT::T_GROUP_IMPORT_BRACE_CLOSE, ] ); } public static function provideProcessCases(): iterable { yield 'curly open/close I' => [ ' T_CURLY_OPEN, 7 => CT::T_CURLY_CLOSE, ], ]; yield 'curly open/close II' => [ 'c()}d";', [ 7 => T_CURLY_OPEN, 13 => CT::T_CURLY_CLOSE, ], ]; yield 'dynamic var brace open/close' => [ ' T_CURLY_OPEN, 7 => CT::T_DYNAMIC_VAR_BRACE_OPEN, 11 => CT::T_DYNAMIC_VAR_BRACE_CLOSE, 12 => CT::T_CURLY_CLOSE, ], ]; yield 'dollar curly brace open/close' => [ ' T_DOLLAR_OPEN_CURLY_BRACES, 7 => CT::T_DOLLAR_CLOSE_CURLY_BRACES, ], ]; yield 'dynamic property brace open/close' => [ '{$bar};', [ 3 => CT::T_DYNAMIC_PROP_BRACE_OPEN, 5 => CT::T_DYNAMIC_PROP_BRACE_CLOSE, ], ]; yield 'dynamic variable brace open/close' => [ ' CT::T_DYNAMIC_VAR_BRACE_OPEN, 4 => CT::T_DYNAMIC_VAR_BRACE_CLOSE, ], ]; yield 'mixed' => [ 'c()}d"; echo "I\'d like an {${beers::$ale}}\n"; ', [ 5 => T_CURLY_OPEN, 7 => CT::T_CURLY_CLOSE, 17 => T_CURLY_OPEN, 23 => CT::T_CURLY_CLOSE, 32 => T_CURLY_OPEN, 34 => CT::T_DYNAMIC_VAR_BRACE_OPEN, 38 => CT::T_DYNAMIC_VAR_BRACE_CLOSE, 39 => CT::T_CURLY_CLOSE, ], ]; yield 'do not touch' => [ ' [ '{"set_{$name}"}(42);', [ 3 => CT::T_DYNAMIC_PROP_BRACE_OPEN, 6 => T_CURLY_OPEN, 8 => CT::T_CURLY_CLOSE, 10 => CT::T_DYNAMIC_PROP_BRACE_CLOSE, ], ]; yield 'group import' => [ ' CT::T_GROUP_IMPORT_BRACE_OPEN, 19 => CT::T_GROUP_IMPORT_BRACE_CLOSE, ], ]; yield 'nested curly open + close' => [ '{"{$bar}"}}";', [ 4 => T_CURLY_OPEN, 7 => CT::T_DYNAMIC_PROP_BRACE_OPEN, 9 => T_CURLY_OPEN, 11 => CT::T_CURLY_CLOSE, 13 => CT::T_DYNAMIC_PROP_BRACE_CLOSE, 14 => CT::T_CURLY_CLOSE, ], ]; } /** * @param _TransformerTestExpectedTokens $expectedTokens * * @dataProvider provideProcess80Cases * * @requires PHP 8.0 */ public function testProcess80(string $source, array $expectedTokens = []): void { $this->doTest( $source, $expectedTokens, [ T_CURLY_OPEN, CT::T_CURLY_CLOSE, T_DOLLAR_OPEN_CURLY_BRACES, CT::T_DOLLAR_CLOSE_CURLY_BRACES, CT::T_DYNAMIC_PROP_BRACE_OPEN, CT::T_DYNAMIC_PROP_BRACE_CLOSE, CT::T_DYNAMIC_VAR_BRACE_OPEN, CT::T_DYNAMIC_VAR_BRACE_CLOSE, CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, CT::T_GROUP_IMPORT_BRACE_OPEN, CT::T_GROUP_IMPORT_BRACE_CLOSE, ] ); } public static function provideProcess80Cases(): iterable { yield 'dynamic nullable property brace open/close' => [ '{$bar};', [ 3 => CT::T_DYNAMIC_PROP_BRACE_OPEN, 5 => CT::T_DYNAMIC_PROP_BRACE_CLOSE, ], ]; } /** * @param _TransformerTestExpectedTokens $expectedTokens * * @dataProvider providePre84ProcessCases * * @requires PHP <8.4 */ public function testPre84Process(string $source, array $expectedTokens = []): void { $this->doTest( $source, $expectedTokens, [ T_CURLY_OPEN, CT::T_CURLY_CLOSE, T_DOLLAR_OPEN_CURLY_BRACES, CT::T_DOLLAR_CLOSE_CURLY_BRACES, CT::T_DYNAMIC_PROP_BRACE_OPEN, CT::T_DYNAMIC_PROP_BRACE_CLOSE, CT::T_DYNAMIC_VAR_BRACE_OPEN, CT::T_DYNAMIC_VAR_BRACE_CLOSE, CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, CT::T_GROUP_IMPORT_BRACE_OPEN, CT::T_GROUP_IMPORT_BRACE_CLOSE, ] ); } /** * @return iterable}> */ public static function providePre84ProcessCases(): iterable { yield 'array index curly brace open/close' => [ ' CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, 7 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, ], ]; yield 'array index curly brace open/close, after square index' => [ ' CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, 10 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, ], ]; yield 'array index curly brace open/close, nested' => [ ' CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, 7 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, 8 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, 10 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, 14 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, 16 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, ], ]; yield 'array index curly brace open/close, repeated' => [ 'foo; echo $collection->items{1}->property; ', [ 5 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, 7 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, 17 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, 19 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, ], ]; yield 'array index curly brace open/close, minimal' => [ ' CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, 9 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, 18 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, 20 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, ], ]; } /** * @dataProvider provideNotDynamicClassConstantFetchCases */ public function testNotDynamicClassConstantFetch(string $source): void { Tokens::clearCache(); $tokens = Tokens::fromCode($source); self::assertFalse( $tokens->isAnyTokenKindsFound( [ CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ] ) ); } /** * @return iterable */ public static function provideNotDynamicClassConstantFetchCases(): iterable { yield 'negatives' => [ 'doTest( $source, $expectedTokens, [ CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], ); } public static function provideDynamicClassConstantFetchCases(): iterable { yield 'simple' => [ [ 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 7 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], ' [ [ 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 7 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], " [ [ 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 10 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], '', ]; yield 'variable variable, comment' => [ [ 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 8 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], '', ]; yield 'static, self' => [ [ 37 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 39 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, 46 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 48 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, 55 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 57 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], ' [ [ 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 7 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, 9 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 11 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], "", ]; yield 'mixed chain' => [ [ 21 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 23 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, 25 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 27 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], 'doTest( $source, $expectedTokens, [ CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], ); } /** * @return iterable, string}> */ public static function provideDynamicClassConstantFetchPhp83Cases(): iterable { yield 'static method var, string' => [ [ 10 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 12 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], " [ [ 17 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 19 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, 21 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 23 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, 25 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, 27 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, ], '