123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- <?php
- declare(strict_types=1);
- /*
- * This file is part of PHP CS Fixer.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- * Dariusz Rumiński <dariusz.ruminski@gmail.com>
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
- namespace PhpCsFixer\Tests\Fixer\ConstantNotation;
- use PhpCsFixer\ConfigurationException\InvalidConfigurationException;
- use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
- /**
- * @author Filippo Tessarotto <zoeslam@gmail.com>
- *
- * @internal
- *
- * @covers \PhpCsFixer\Fixer\ConstantNotation\NativeConstantInvocationFixer
- *
- * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\ConstantNotation\NativeConstantInvocationFixer>
- *
- * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\ConstantNotation\NativeConstantInvocationFixer
- */
- final class NativeConstantInvocationFixerTest extends AbstractFixerTestCase
- {
- public function testConfigureRejectsUnknownConfigurationKey(): void
- {
- $key = 'foo';
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage(\sprintf('[native_constant_invocation] Invalid configuration: The option "%s" does not exist.', $key));
- $this->fixer->configure([
- $key => 'bar',
- ]);
- }
- /**
- * @dataProvider provideInvalidConfigurationElementCases
- *
- * @param mixed $element
- */
- public function testConfigureRejectsInvalidExcludeConfigurationElement($element, string $expectedExceptionMessage): void
- {
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage($expectedExceptionMessage);
- $this->fixer->configure([
- 'exclude' => [
- $element,
- ],
- ]);
- }
- /**
- * @dataProvider provideInvalidConfigurationElementCases
- *
- * @param mixed $element
- */
- public function testConfigureRejectsInvalidIncludeConfigurationElement($element, string $expectedExceptionMessage): void
- {
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage(
- str_replace('"exclude"', '"include"', $expectedExceptionMessage)
- );
- $this->fixer->configure([
- 'include' => [
- $element,
- ],
- ]);
- }
- public static function provideInvalidConfigurationElementCases(): iterable
- {
- yield 'null' => [
- null,
- '[native_constant_invocation] Invalid configuration: The option "exclude" with value array is expected to be of type "string[]", but one of the elements is of type "null".',
- ];
- yield 'false' => [
- false,
- '[native_constant_invocation] Invalid configuration: The option "exclude" with value array is expected to be of type "string[]", but one of the elements is of type "bool".',
- ];
- yield 'true' => [
- true,
- '[native_constant_invocation] Invalid configuration: The option "exclude" with value array is expected to be of type "string[]", but one of the elements is of type "bool".',
- ];
- yield 'int' => [
- 1,
- '[native_constant_invocation] Invalid configuration: The option "exclude" with value array is expected to be of type "string[]", but one of the elements is of type "int".',
- ];
- yield 'array' => [
- [],
- '[native_constant_invocation] Invalid configuration: The option "exclude" with value array is expected to be of type "string[]", but one of the elements is of type "array".',
- ];
- yield 'float' => [
- 0.1,
- '[native_constant_invocation] Invalid configuration: The option "exclude" with value array is expected to be of type "string[]", but one of the elements is of type "float".',
- ];
- yield 'object' => [
- new \stdClass(),
- '[native_constant_invocation] Invalid configuration: The option "exclude" with value array is expected to be of type "string[]", but one of the elements is of type "stdClass".',
- ];
- yield 'not-trimmed' => [
- ' M_PI ',
- '[native_constant_invocation] Invalid configuration: Each element must be a non-empty, trimmed string, got "string" instead.',
- ];
- }
- public function testConfigureResetsExclude(): void
- {
- $this->fixer->configure([
- 'exclude' => [
- 'M_PI',
- ],
- ]);
- $before = '<?php var_dump(m_pi, M_PI);';
- $after = '<?php var_dump(m_pi, \M_PI);';
- $this->doTest($before);
- $this->fixer->configure([]);
- $this->doTest($after, $before);
- }
- /**
- * @dataProvider provideFixWithDefaultConfigurationCases
- */
- public function testFixWithDefaultConfiguration(string $expected, ?string $input = null): void
- {
- $this->doTest($expected, $input);
- }
- /**
- * @return iterable<array{0: string, 1?: string}>
- */
- public static function provideFixWithDefaultConfigurationCases(): iterable
- {
- yield ['<?php var_dump(NULL, FALSE, TRUE, 1);'];
- yield ['<?php echo CUSTOM_DEFINED_CONSTANT_123;'];
- yield ['<?php echo m_pi; // Constant are case sensitive'];
- yield ['<?php namespace M_PI;'];
- yield ['<?php namespace Foo; use M_PI;'];
- yield ['<?php class M_PI {}'];
- yield ['<?php class Foo extends M_PI {}'];
- yield ['<?php class Foo implements M_PI {}'];
- yield ['<?php interface M_PI {};'];
- yield ['<?php trait M_PI {};'];
- yield ['<?php class Foo { const M_PI = 1; }'];
- yield ['<?php class Foo { use M_PI; }'];
- yield ['<?php class Foo { public $M_PI = 1; }'];
- yield ['<?php class Foo { function M_PI($M_PI) {} }'];
- yield ['<?php class Foo { function bar() { $M_PI = M_PI() + self::M_PI(); } }'];
- yield ['<?php class Foo { function bar() { $this->M_PI(self::M_PI); } }'];
- yield ['<?php namespace Foo; use Bar as M_PI;'];
- yield ['<?php echo Foo\M_PI\Bar;'];
- yield ['<?php M_PI::foo();'];
- yield ['<?php function x(M_PI $foo, M_PI &$bar, M_PI ...$baz) {}'];
- yield ['<?php $foo instanceof M_PI;'];
- yield ['<?php class x implements FOO, M_PI, BAZ {}'];
- yield ['<?php class Foo { use Bar, M_PI { Bar::baz insteadof M_PI; } }'];
- yield ['<?php M_PI: goto M_PI;'];
- yield [
- '<?php echo \M_PI;',
- '<?php echo M_PI;',
- ];
- yield [
- '<?php namespace Foo; use M_PI; echo \M_PI;',
- '<?php namespace Foo; use M_PI; echo M_PI;',
- ];
- yield [
- // Here we are just testing the algorithm.
- // A user likely would add this M_PI to its excluded list.
- '<?php namespace M_PI; const M_PI = 1; return \M_PI;',
- '<?php namespace M_PI; const M_PI = 1; return M_PI;',
- ];
- yield [
- '<?php foo(\E_DEPRECATED | \E_USER_DEPRECATED);',
- '<?php foo(E_DEPRECATED | E_USER_DEPRECATED);',
- ];
- yield ['<?php function foo(): M_PI {}'];
- yield ['<?php use X\Y\{FOO, BAR as BAR2, M_PI};'];
- yield [
- '<?php
- try {
- foo(\JSON_ERROR_DEPTH|\JSON_PRETTY_PRINT|JOB_QUEUE_PRIORITY_HIGH);
- } catch (\Exception | \InvalidArgumentException|\UnexpectedValueException|LogicException $e) {
- }
- ',
- '<?php
- try {
- foo(\JSON_ERROR_DEPTH|JSON_PRETTY_PRINT|\JOB_QUEUE_PRIORITY_HIGH);
- } catch (\Exception | \InvalidArgumentException|\UnexpectedValueException|LogicException $e) {
- }
- ',
- ];
- }
- /**
- * @dataProvider provideFixWithConfiguredCustomIncludeCases
- */
- public function testFixWithConfiguredCustomInclude(string $expected, ?string $input = null): void
- {
- $this->fixer->configure([
- 'include' => [
- 'FOO_BAR_BAZ',
- ],
- ]);
- $this->doTest($expected, $input);
- }
- /**
- * @return iterable<array{string, string}>
- */
- public static function provideFixWithConfiguredCustomIncludeCases(): iterable
- {
- yield [
- '<?php echo \FOO_BAR_BAZ . \M_PI;',
- '<?php echo FOO_BAR_BAZ . M_PI;',
- ];
- yield [
- '<?php class Foo { public function bar($foo) { return \FOO_BAR_BAZ . \M_PI; } }',
- '<?php class Foo { public function bar($foo) { return FOO_BAR_BAZ . M_PI; } }',
- ];
- }
- /**
- * @dataProvider provideFixWithConfiguredOnlyIncludeCases
- */
- public function testFixWithConfiguredOnlyInclude(string $expected, ?string $input = null): void
- {
- $this->fixer->configure([
- 'fix_built_in' => false,
- 'include' => [
- 'M_PI',
- ],
- ]);
- $this->doTest($expected, $input);
- }
- /**
- * @return iterable<array{string, string}>
- */
- public static function provideFixWithConfiguredOnlyIncludeCases(): iterable
- {
- yield [
- '<?php echo PHP_SAPI . FOO_BAR_BAZ . \M_PI;',
- '<?php echo PHP_SAPI . FOO_BAR_BAZ . M_PI;',
- ];
- yield [
- '<?php class Foo { public function bar($foo) { return PHP_SAPI . FOO_BAR_BAZ . \M_PI; } }',
- '<?php class Foo { public function bar($foo) { return PHP_SAPI . FOO_BAR_BAZ . M_PI; } }',
- ];
- }
- /**
- * @dataProvider provideFixWithConfiguredExcludeCases
- */
- public function testFixWithConfiguredExclude(string $expected, ?string $input = null): void
- {
- $this->fixer->configure([
- 'exclude' => [
- 'M_PI',
- ],
- ]);
- $this->doTest($expected, $input);
- }
- /**
- * @return iterable<array{string, string}>
- */
- public static function provideFixWithConfiguredExcludeCases(): iterable
- {
- yield [
- '<?php echo \PHP_SAPI . M_PI;',
- '<?php echo PHP_SAPI . M_PI;',
- ];
- yield [
- '<?php class Foo { public function bar($foo) { return \PHP_SAPI . M_PI; } }',
- '<?php class Foo { public function bar($foo) { return PHP_SAPI . M_PI; } }',
- ];
- }
- public function testNullTrueFalseAreCaseInsensitive(): void
- {
- $this->fixer->configure([
- 'fix_built_in' => false,
- 'include' => [
- 'null',
- 'false',
- 'M_PI',
- 'M_pi',
- ],
- 'exclude' => [],
- ]);
- $expected = <<<'EOT'
- <?php
- var_dump(
- \null,
- \NULL,
- \Null,
- \nUlL,
- \false,
- \FALSE,
- true,
- TRUE,
- \M_PI,
- \M_pi,
- m_pi,
- m_PI
- );
- EOT;
- $input = <<<'EOT'
- <?php
- var_dump(
- null,
- NULL,
- Null,
- nUlL,
- false,
- FALSE,
- true,
- TRUE,
- M_PI,
- M_pi,
- m_pi,
- m_PI
- );
- EOT;
- $this->doTest($expected, $input);
- }
- public function testDoNotIncludeUserConstantsUnlessExplicitlyListed(): void
- {
- $uniqueConstantName = uniqid(self::class);
- $uniqueConstantName = preg_replace('/\W+/', '_', $uniqueConstantName);
- $uniqueConstantName = strtoupper($uniqueConstantName);
- $dontFixMe = 'DONTFIXME_'.$uniqueConstantName;
- $fixMe = 'FIXME_'.$uniqueConstantName;
- \define($dontFixMe, 1);
- \define($fixMe, 1);
- $this->fixer->configure([
- 'fix_built_in' => true,
- 'include' => [
- $fixMe,
- ],
- 'exclude' => [],
- ]);
- $expected = <<<EOT
- <?php
- var_dump(
- \\null,
- {$dontFixMe},
- \\{$fixMe}
- );
- EOT;
- $input = <<<EOT
- <?php
- var_dump(
- null,
- {$dontFixMe},
- {$fixMe}
- );
- EOT;
- $this->doTest($expected, $input);
- }
- public function testDoNotFixImportedConstants(): void
- {
- $this->fixer->configure([
- 'fix_built_in' => false,
- 'include' => [
- 'M_PI',
- 'M_EULER',
- ],
- 'exclude' => [],
- ]);
- $expected = <<<'EOT'
- <?php
- namespace Foo;
- use const M_EULER;
- var_dump(
- null,
- \M_PI,
- M_EULER
- );
- EOT;
- $input = <<<'EOT'
- <?php
- namespace Foo;
- use const M_EULER;
- var_dump(
- null,
- M_PI,
- M_EULER
- );
- EOT;
- $this->doTest($expected, $input);
- }
- public function testFixScopedOnly(): void
- {
- $this->fixer->configure(['scope' => 'namespaced']);
- $expected = <<<'EOT'
- <?php
- namespace space1 {
- echo \PHP_VERSION;
- }
- namespace {
- echo PHP_VERSION;
- }
- EOT;
- $input = <<<'EOT'
- <?php
- namespace space1 {
- echo PHP_VERSION;
- }
- namespace {
- echo PHP_VERSION;
- }
- EOT;
- $this->doTest($expected, $input);
- }
- public function testFixScopedOnlyNoNamespace(): void
- {
- $this->fixer->configure(['scope' => 'namespaced']);
- $expected = <<<'EOT'
- <?php
- echo PHP_VERSION . PHP_EOL;
- EOT;
- $this->doTest($expected);
- }
- public function testFixStrictOption(): void
- {
- $this->fixer->configure(['strict' => true]);
- $this->doTest(
- '<?php
- echo \PHP_VERSION . \PHP_EOL; // built-in constants to have backslash
- echo MY_FRAMEWORK_MAJOR_VERSION . MY_FRAMEWORK_MINOR_VERSION; // non-built-in constants not to have backslash
- echo \Dont\Touch\Namespaced\CONSTANT;
- ',
- '<?php
- echo \PHP_VERSION . PHP_EOL; // built-in constants to have backslash
- echo \MY_FRAMEWORK_MAJOR_VERSION . MY_FRAMEWORK_MINOR_VERSION; // non-built-in constants not to have backslash
- echo \Dont\Touch\Namespaced\CONSTANT;
- '
- );
- }
- /**
- * @requires PHP <8.0
- */
- public function testFixPrePHP80(): void
- {
- $this->doTest(
- '<?php
- echo \/**/M_PI;
- echo \ M_PI;
- echo \#
- #
- M_PI;
- echo \M_PI;
- ',
- '<?php
- echo \/**/M_PI;
- echo \ M_PI;
- echo \#
- #
- M_PI;
- echo M_PI;
- '
- );
- }
- /**
- * @dataProvider provideFixPhp80Cases
- *
- * @requires PHP 8.0
- */
- public function testFixPhp80(string $expected): void
- {
- $this->fixer->configure(['strict' => true]);
- $this->doTest($expected);
- }
- /**
- * @return iterable<array{string}>
- */
- public static function provideFixPhp80Cases(): iterable
- {
- yield [
- '<?php
- try {
- } catch (\Exception) {
- }',
- ];
- yield ['<?php try { foo(); } catch(\InvalidArgumentException|\LogicException $e) {}'];
- yield ['<?php try { foo(); } catch(\InvalidArgumentException|\LogicException) {}'];
- }
- /**
- * @dataProvider provideFixPhp81Cases
- *
- * @requires PHP 8.1
- */
- public function testFixPhp81(string $expected): void
- {
- $this->fixer->configure(['strict' => true]);
- $this->doTest($expected);
- }
- /**
- * @return iterable<array{string}>
- */
- public static function provideFixPhp81Cases(): iterable
- {
- yield [
- '<?php enum someEnum: int
- {
- case E_ALL = 123;
- }',
- ];
- }
- /**
- * @dataProvider provideFixPhp82Cases
- *
- * @requires PHP 8.2
- */
- public function testFixPhp82(string $expected): void
- {
- $this->fixer->configure(['strict' => true]);
- $this->doTest($expected);
- }
- /**
- * @return iterable<array{0: string}>
- */
- public static function provideFixPhp82Cases(): iterable
- {
- yield ['<?php class Foo { public (\A&B)|(C&\D)|E\F|\G|(A&H\I)|(A&\J\K) $var; }'];
- yield ['<?php function foo ((\A&B)|(C&\D)|E\F|\G|(A&H\I)|(A&\J\K) $var) {}'];
- }
- /**
- * @dataProvider provideFixPhp83Cases
- *
- * @requires PHP 8.3
- */
- public function testFixPhp83(string $expected, string $input): void
- {
- $this->fixer->configure(['strict' => true]);
- $this->doTest($expected, $input);
- }
- /**
- * @return iterable<array{0: string, 1: string}>
- */
- public static function provideFixPhp83Cases(): iterable
- {
- yield [
- '<?php class Foo {
- public const string C1 = \PHP_EOL;
- protected const string|int C2 = \PHP_EOL;
- private const string|(A&B) C3 = BAR;
- public const EnumA C4 = EnumA::FOO;
- private const array CONNECTION_TIMEOUT = [\'foo\'];
- }',
- '<?php class Foo {
- public const string C1 = PHP_EOL;
- protected const string|int C2 = \PHP_EOL;
- private const string|(A&B) C3 = \BAR;
- public const EnumA C4 = EnumA::FOO;
- private const array CONNECTION_TIMEOUT = [\'foo\'];
- }',
- ];
- }
- }
|