* 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\ControlStructure; use PhpCsFixer\AbstractNoUselessElseFixer; use PhpCsFixer\Tests\Test\AbstractFixerTestCase; use PhpCsFixer\Tokenizer\Tokens; /** * @internal * * @covers \PhpCsFixer\AbstractNoUselessElseFixer * @covers \PhpCsFixer\Fixer\ControlStructure\NoUselessElseFixer * * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\ControlStructure\NoUselessElseFixer> */ final class NoUselessElseFixerTest extends AbstractFixerTestCase { /** * @dataProvider provideCloseTagCases */ public function testCloseTag(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } /** * @return iterable */ public static function provideCloseTagCases(): iterable { yield [ ' 2 ? "" : die ?> 2 ? "" : die ?> doTest($expected, $input); } /** * @return iterable */ public static function provideFixIfElseIfElseCases(): iterable { $expected = 'doTest($expected, $input); } /** * @return iterable */ public static function provideFixIfElseCases(): iterable { $expected = 'doTest($expected, $input); } /** * @return iterable */ public static function provideFixNestedIfCases(): iterable { yield [ 'doTest($expected, $input); } /** * @return iterable */ public static function provideFixEmptyElseCases(): iterable { yield [ 'doTest($expected); } /** * @return iterable */ public static function provideNegativeCases(): iterable { yield [ ' 2) { return 1; } else { $a--; } }); ', ]; yield [ ' 2) { } else { echo 1; } };', ]; yield [ ' 2) { } else { echo 1; } };', ]; } /** * @dataProvider provideNegativePhp80Cases * * @requires PHP 8.0 */ public function testNegativePhp80(string $expected): void { $this->doTest($expected); } /** * @return iterable */ public static function provideNegativePhp80Cases(): iterable { $cases = [ '$bar = $foo1 ?? throw new \Exception($e);', '$callable = fn() => throw new Exception();', '$value = $falsableValue ?: throw new InvalidArgumentException();', '$value = !empty($array) ? reset($array) : throw new InvalidArgumentException();', '$a = $condition && throw new Exception();', '$a = $condition || throw new Exception();', '$a = $condition and throw new Exception();', '$a = $condition or throw new Exception();', ]; $template = ' $case) { yield \sprintf('PHP8 Negative case %d', $index) => [\sprintf($template, $case)]; } } /** * @param list $expected * * @dataProvider provideBlockDetectionCases */ public function testBlockDetection(array $expected, string $source, int $index): void { Tokens::clearCache(); $tokens = Tokens::fromCode($source); $result = \Closure::bind(static fn (AbstractNoUselessElseFixer $fixer): array => $fixer->getPreviousBlock($tokens, $index), null, AbstractNoUselessElseFixer::class)($this->fixer); self::assertSame($expected, $result); } public static function provideBlockDetectionCases(): iterable { $source = 'doTest($expected, $input); } /** * @return iterable */ public static function provideConditionsWithoutBracesCases(): iterable { $statements = [ 'die;', 'throw new Exception($i);', 'while($i < 1) throw/*{}*/new Exception($i);', 'while($i < 1){throw new Exception($i);}', 'do{throw new Exception($i);}while($i < 1);', 'foreach($a as $b)throw new Exception($i);', 'foreach($a as $b){throw new Exception($i);}', ]; foreach ($statements as $statement) { yield from self::generateConditionsWithoutBracesCase($statement); } yield [ 'doTest($expected); } /** * @return iterable */ public static function provideConditionsWithoutBraces80Cases(): iterable { yield from self::generateConditionsWithoutBracesCase('$b = $a ?? throw new Exception($i);'); } /** * @param array $indexes * * @dataProvider provideIsInConditionWithoutBracesCases */ public function testIsInConditionWithoutBraces(array $indexes, string $input): void { $tokens = Tokens::fromCode($input); foreach ($indexes as $index => $expected) { self::assertSame( $expected, \Closure::bind(static fn (AbstractNoUselessElseFixer $fixer): bool => $fixer->isInConditionWithoutBraces($tokens, $index, 0), null, AbstractNoUselessElseFixer::class)($this->fixer), \sprintf('Failed in condition without braces check for index %d', $index) ); } } public static function provideIsInConditionWithoutBracesCases(): iterable { yield [ [ 18 => false, // return 25 => false, // return 36 => false, // return ], ' false, 29 => false, // throw ], ' false, 38 => true, // throw ], ' false, 26 => true, // throw 28 => true, // new 30 => true, // Exception ], ' false, 30 => true, // throw 32 => true, // new 34 => true, // Exception ], ' false, 25 => true, // throw 27 => true, // new 29 => true, // Exception ], ' true, // throw ], ' false, // 1 13 => true, // if (2nd) 21 => true, // true 33 => true, // while 43 => false, // echo 45 => false, // 2 46 => false, // ; 51 => false, // echo (123) ], ' false, // echo 13 => true, // echo 15 => true, // 2 20 => true, // die 23 => false, // echo ], ' true, // die 9 => true, // /**/ 15 => true, // die ], ' true, // die 9 => true, // /**/ 15 => true, // die ], ' ', ]; } /** * @return iterable */ private static function generateConditionsWithoutBracesCase(string $statement): iterable { $ifTemplate = ' */ private static function generateCases(string $expected, ?string $input = null): iterable { $cases = []; foreach ([ 'exit;', 'exit();', 'exit(1);', 'die;', 'die();', 'die(1);', 'break;', 'break 2;', 'break (2);', 'continue;', 'continue 2;', 'continue (2);', 'return;', 'return 1;', 'return (1);', 'return "a";', 'return 8+2;', 'return null;', 'return sum(1+8*6, 2);', 'throw $e;', 'throw ($e);', 'throw new \Exception;', 'throw new \Exception();', 'throw new \Exception((string)12+1);', ] as $case) { if (null === $input) { $cases[] = [\sprintf($expected, $case)]; $cases[] = [\sprintf($expected, strtoupper($case))]; if ($case !== strtolower($case)) { $cases[] = [\sprintf($expected, strtolower($case))]; } } else { $cases[] = [\sprintf($expected, $case), \sprintf($input, $case)]; $cases[] = [\sprintf($expected, strtoupper($case)), \sprintf($input, strtoupper($case))]; if ($case !== strtolower($case)) { $cases[] = [\sprintf($expected, strtolower($case)), \sprintf($input, strtolower($case))]; } } } return $cases; } }