VisibilityRequiredFixerTest.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Tests\Fixer\ClassNotation;
  13. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  14. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  15. /**
  16. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  17. *
  18. * @internal
  19. *
  20. * @covers \PhpCsFixer\Fixer\ClassNotation\VisibilityRequiredFixer
  21. */
  22. final class VisibilityRequiredFixerTest extends AbstractFixerTestCase
  23. {
  24. public function testFixProperties(): void
  25. {
  26. $expected = <<<'EOF'
  27. <?php
  28. class Foo {
  29. public $var;
  30. protected $var_foo;
  31. private $FooBar;
  32. public static $var1;
  33. protected static $var_foo2;
  34. private static $FooBar1;
  35. public static $var2;
  36. protected static $var_foo3;
  37. private static $FooBar2;
  38. private static $FooBar3;
  39. public $old = 'foo';
  40. }
  41. EOF;
  42. $input = <<<'EOF'
  43. <?php
  44. class Foo {
  45. public $var;
  46. protected $var_foo;
  47. private $FooBar;
  48. static public $var1;
  49. static protected $var_foo2;
  50. static private $FooBar1;
  51. public static $var2;
  52. protected static $var_foo3;
  53. private static $FooBar2;
  54. private static
  55. $FooBar3;
  56. var $old = 'foo';
  57. }
  58. EOF;
  59. $this->doTest($expected, $input);
  60. }
  61. public function testFixPropertiesAfterMethod(): void
  62. {
  63. $input = <<<'EOF'
  64. <?php
  65. class Foo {
  66. public function aaa() {}
  67. var $bbb;
  68. }
  69. EOF;
  70. $expected = <<<'EOF'
  71. <?php
  72. class Foo {
  73. public function aaa() {}
  74. public $bbb;
  75. }
  76. EOF;
  77. $this->doTest($expected, $input);
  78. }
  79. /**
  80. * @dataProvider provideFixMethodsCases
  81. */
  82. public function testFixMethods(string $expected, string $input = null): void
  83. {
  84. $this->doTest($expected, $input);
  85. }
  86. public static function provideFixMethodsCases(): iterable
  87. {
  88. yield [
  89. <<<'EOF'
  90. <?php
  91. class MyTestWithAnonymousClass extends TestCase
  92. {
  93. public function setUp()
  94. {
  95. $provider = new class(function () {}) {};
  96. }
  97. public function testSomethingWithMoney(
  98. Money $amount
  99. ) {
  100. }
  101. }
  102. EOF
  103. ,
  104. <<<'EOF'
  105. <?php
  106. class MyTestWithAnonymousClass extends TestCase
  107. {
  108. function setUp()
  109. {
  110. $provider = new class(function () {}) {};
  111. }
  112. public function testSomethingWithMoney(
  113. Money $amount
  114. ) {
  115. }
  116. }
  117. EOF
  118. ,
  119. ];
  120. yield [
  121. <<<'EOF'
  122. <?php
  123. abstract class Foo {
  124. public function& foo0() {}
  125. public function & foo1() {}
  126. public function &foo2() {}
  127. protected function foo3($b) {}
  128. abstract protected function foo4();
  129. private function foo5() {}
  130. final public function foo6() {}
  131. abstract public function foo7();
  132. final public function foo8() {}
  133. abstract public function foo9();
  134. public static function fooA() {}
  135. public static function fooD() {}
  136. final public static function fooE() {}
  137. abstract public function fooF();
  138. public function fooG ($foo) {}
  139. public function fooH() {
  140. static $foo;
  141. $bar = function($baz) {};
  142. }
  143. }
  144. EOF
  145. ,
  146. <<<'EOF'
  147. <?php
  148. abstract class Foo {
  149. public function& foo0() {}
  150. public function & foo1() {}
  151. function &foo2() {}
  152. protected function foo3($b) {}
  153. protected
  154. abstract function foo4();
  155. private function foo5() {}
  156. final public function foo6() {}
  157. abstract public function foo7();
  158. public final function foo8() {}
  159. public abstract function foo9();
  160. public static function fooA() {}
  161. public static
  162. function fooD() {}
  163. final static function fooE() {}
  164. abstract function fooF();
  165. function fooG ($foo) {}
  166. function fooH() {
  167. static $foo;
  168. $bar = function($baz) {};
  169. }
  170. }
  171. EOF
  172. ,
  173. ];
  174. yield [
  175. <<<'EOF'
  176. <?php
  177. abstract class Foo1 {
  178. public function& foo0($a) {}
  179. }
  180. EOF
  181. ,
  182. <<<'EOF'
  183. <?php
  184. abstract class Foo1 {
  185. function& foo0($a) {}
  186. }
  187. EOF
  188. ,
  189. ];
  190. }
  191. public function testLeaveFunctionsAlone(): void
  192. {
  193. $expected = <<<'EOF'
  194. <?php
  195. function foo() {
  196. static $foo;
  197. }
  198. EOF;
  199. $this->doTest($expected);
  200. }
  201. public function testLeaveFunctionsAloneWithVariablesMatchingOopWords(): void
  202. {
  203. $expected = <<<'EOF'
  204. <?php
  205. function foo() {
  206. static $class;
  207. $interface = 'foo';
  208. $trait = 'bar';
  209. }
  210. EOF;
  211. $this->doTest($expected);
  212. }
  213. public function testLeaveFunctionsAloneInsideConditionals(): void
  214. {
  215. $expected = <<<'EOF'
  216. <?php
  217. if (!function_exists('foo')) {
  218. function foo($arg)
  219. {
  220. return $arg;
  221. }
  222. }
  223. EOF;
  224. $this->doTest($expected);
  225. }
  226. public function testLeaveFunctionsAloneInsideConditionalsWithOopWordInComment(): void
  227. {
  228. $expected = <<<'EOF'
  229. <?php
  230. /* class <= this is just a stop-word */
  231. if (!function_exists('foo')) {
  232. function foo($arg)
  233. {
  234. return $arg;
  235. }
  236. }
  237. EOF;
  238. $this->doTest($expected);
  239. }
  240. public function testLeaveFunctionsAloneWithOopWordInComment(): void
  241. {
  242. $expected = <<<'EOF'
  243. <?php
  244. /* class */
  245. function foo($arg)
  246. {
  247. return $arg;
  248. }
  249. EOF;
  250. $this->doTest($expected);
  251. }
  252. public function testLeaveFunctionsAloneOutsideClassesWithOopWordInInlineHtml(): void
  253. {
  254. $expected = <<<'EOF'
  255. <?php
  256. if (!function_exists('foo')) {
  257. function foo($arg)
  258. {
  259. ?>
  260. <div class="test"></div>
  261. <?php
  262. return $arg;
  263. }
  264. }
  265. EOF;
  266. $this->doTest($expected);
  267. }
  268. public function testLeaveFunctionsAloneOutsideClassesWithOopWordInStringValue(): void
  269. {
  270. $expected = <<<'EOF'
  271. <?php
  272. if (!function_exists('foo')) {
  273. function foo($arg)
  274. {
  275. return 'she has class right?';
  276. }
  277. }
  278. EOF;
  279. $this->doTest($expected);
  280. }
  281. public function testLeaveFunctionsAloneOutsideClassesWithOopWordInFunctionName(): void
  282. {
  283. $expected = <<<'EOF'
  284. <?php
  285. comment_class();
  286. if (!function_exists('foo')) {
  287. function foo($arg)
  288. {
  289. return $arg;
  290. }
  291. }
  292. EOF;
  293. $this->doTest($expected);
  294. }
  295. public function testLeaveFunctionsAloneAfterClass(): void
  296. {
  297. $expected = <<<'EOF'
  298. <?php
  299. class Foo
  300. {
  301. public $foo;
  302. }
  303. if (!function_exists('bar')) {
  304. function bar()
  305. {
  306. return 'bar';
  307. }
  308. }
  309. EOF;
  310. $this->doTest($expected);
  311. }
  312. public function testCurlyOpenSyntax(): void
  313. {
  314. $expected = <<<'EOF'
  315. <?php
  316. class Foo
  317. {
  318. private $bar;
  319. public function foo()
  320. {
  321. $foo = "foo";
  322. $fooA = "ab{$foo}cd";
  323. $bar = "bar"; // test if variable after T_CURLY_OPEN is intact
  324. }
  325. }
  326. EOF;
  327. $this->doTest($expected);
  328. }
  329. public function testDollarOpenCurlyBracesSyntax(): void
  330. {
  331. $expected = <<<'EOF'
  332. <?php
  333. class Foo {
  334. public function bar()
  335. {
  336. $foo = "foo${width}foo";
  337. $bar = "bar"; // test if variable after T_DOLLAR_OPEN_CURLY_BRACES is intact
  338. }
  339. }
  340. EOF;
  341. $this->doTest($expected);
  342. }
  343. public function testLeaveJavascriptOutsidePhpAlone(): void
  344. {
  345. $expected = <<<'EOF'
  346. <?php
  347. function foo()
  348. {
  349. return "foo";
  350. }
  351. ?>
  352. <script type="text/javascript">
  353. function foo(bar) {
  354. alert(bar);
  355. }
  356. </script>
  357. EOF;
  358. $this->doTest($expected);
  359. }
  360. public function testLeaveJavascriptInStringAlone(): void
  361. {
  362. $expected = <<<'EOF'
  363. <?php
  364. function registerJS()
  365. {
  366. echo '<script type="text/javascript">
  367. function foo(bar) {
  368. alert(bar);
  369. }
  370. </script>';
  371. }
  372. EOF;
  373. $this->doTest($expected);
  374. }
  375. public function testLeaveJavascriptInVariableAlone(): void
  376. {
  377. $expected = <<<'EOF'
  378. <?php
  379. class Foo
  380. {
  381. public function bar()
  382. {
  383. $script = <<<JAVASCRIPT
  384. <script type="text/javascript">
  385. function foo(bar) {
  386. alert(bar);
  387. }
  388. </script>
  389. JAVASCRIPT;
  390. return $script;
  391. }
  392. }
  393. EOF;
  394. $this->doTest($expected);
  395. }
  396. public function testFixCommaSeparatedProperty(): void
  397. {
  398. $expected = <<<'EOF'
  399. <?php
  400. class Foo
  401. {
  402. public $foo1;
  403. private $foo2;
  404. protected $bar1, $bar2;
  405. public $baz1 = null, $baz2, $baz3 = false;
  406. public $foo, $bar;
  407. }
  408. EOF;
  409. $input = <<<'EOF'
  410. <?php
  411. class Foo
  412. {
  413. var $foo1;
  414. private $foo2;
  415. protected $bar1, $bar2;
  416. public $baz1 = null, $baz2, $baz3 = false;
  417. var $foo, $bar;
  418. }
  419. EOF;
  420. $this->doTest($expected, $input);
  421. }
  422. public function testFixesVarDeclarationsWithArrayValue(): void
  423. {
  424. $expected = <<<'EOF'
  425. <?php
  426. class Foo
  427. {
  428. public $foo1 = 1;
  429. public $foo2a = array('foo');
  430. public $foo2b = ['foo'];
  431. public $foo3a = array('foo', 'bar');
  432. public $foo3b = ['foo', 'bar'];
  433. public $foo4a = '1a', $foo5a = array(1, 2, 3), $foo6a = 10;
  434. public $foo4b = '1b', $foo5b = array(1, 2, 3), $foo6b = 10;
  435. }
  436. EOF;
  437. $input = <<<'EOF'
  438. <?php
  439. class Foo
  440. {
  441. var $foo1 = 1;
  442. var $foo2a = array('foo');
  443. var $foo2b = ['foo'];
  444. var $foo3a = array('foo', 'bar');
  445. var $foo3b = ['foo', 'bar'];
  446. public $foo4a = '1a', $foo5a = array(1, 2, 3), $foo6a = 10;
  447. public $foo4b = '1b', $foo5b = array(1, 2, 3), $foo6b = 10;
  448. }
  449. EOF;
  450. $this->doTest($expected, $input);
  451. }
  452. public function testInvalidConfigurationType(): void
  453. {
  454. $this->expectException(InvalidFixerConfigurationException::class);
  455. $this->expectExceptionMessageMatches('/^\[visibility_required\] Invalid configuration: The option "elements" .*\.$/');
  456. $this->fixer->configure(['elements' => [null]]);
  457. }
  458. public function testInvalidConfigurationValue(): void
  459. {
  460. $this->expectException(InvalidFixerConfigurationException::class);
  461. $this->expectExceptionMessageMatches('/^\[visibility_required\] Invalid configuration: The option "elements" .*\.$/');
  462. $this->fixer->configure(['elements' => ['_unknown_']]);
  463. }
  464. /**
  465. * @dataProvider provideFixClassConstCases
  466. */
  467. public function testFixClassConst(string $expected, string $input): void
  468. {
  469. $this->fixer->configure(['elements' => ['const']]);
  470. $this->doTest($expected, $input);
  471. }
  472. public static function provideFixClassConstCases(): iterable
  473. {
  474. yield [
  475. '<?php class A { public const B=1; }',
  476. '<?php class A { const B=1; }',
  477. ];
  478. yield [
  479. '<?php class A { public const B=1;public const C=1;/**/public const#a
  480. D=1;public const E=1;//
  481. public const F=1; }',
  482. '<?php class A { const B=1;const C=1;/**/const#a
  483. D=1;const E=1;//
  484. const F=1; }',
  485. ];
  486. yield [
  487. '<?php class A { private const B=1; protected const C=2; public const D=4; public $a; function A(){} }',
  488. '<?php class A { private const B=1; protected const C=2; const D=4; public $a; function A(){} }',
  489. ];
  490. yield [
  491. '<?php
  492. class foo
  493. {
  494. public const A = 1, B =2, C =3;
  495. public const TWO = ONE * 2;
  496. public const THREE = ONE + self::TWO;
  497. public const SENTENCE = "The value of THREE is ".self::THREE;
  498. }
  499. ',
  500. '<?php
  501. class foo
  502. {
  503. const A = 1, B =2, C =3;
  504. const TWO = ONE * 2;
  505. const THREE = ONE + self::TWO;
  506. const SENTENCE = "The value of THREE is ".self::THREE;
  507. }
  508. ',
  509. ];
  510. }
  511. public function testComment(): void
  512. {
  513. $expected = '<?php
  514. class A
  515. {# We will have a function below
  516. # It will be static
  517. # and awesome
  518. public static function# <- this is the function
  519. AB# <- this is the name
  520. (#
  521. )#
  522. {#
  523. }#
  524. }
  525. ';
  526. $input = '<?php
  527. class A
  528. {# We will have a function below
  529. static# It will be static
  530. # and awesome
  531. function# <- this is the function
  532. AB# <- this is the name
  533. (#
  534. )#
  535. {#
  536. }#
  537. }
  538. ';
  539. $this->doTest($expected, $input);
  540. }
  541. public function testAnonymousClassFixing(): void
  542. {
  543. $this->doTest(
  544. '<?php
  545. $a = new class() {
  546. public function a() {
  547. }
  548. };
  549. class C
  550. {
  551. public function A()
  552. {
  553. $a = new class() {public function a() {}};
  554. }
  555. }
  556. ',
  557. '<?php
  558. $a = new class() {
  559. function a() {
  560. }
  561. };
  562. class C
  563. {
  564. function A()
  565. {
  566. $a = new class() {function a() {}};
  567. }
  568. }
  569. '
  570. );
  571. }
  572. public function testRemovingNewlinesBetweenKeywords(): void
  573. {
  574. $this->doTest(
  575. '<?php
  576. class Foo
  577. {
  578. public $bar;
  579. final public static function bar() {}
  580. final public static function baz() {}
  581. }',
  582. '<?php
  583. class Foo
  584. {
  585. var
  586. $bar;
  587. final
  588. public
  589. static
  590. function bar() {}
  591. static
  592. final
  593. function baz() {}
  594. }'
  595. );
  596. }
  597. public function testKeepingComment(): void
  598. {
  599. $this->fixer->configure(['elements' => ['property', 'method', 'const']]);
  600. $this->doTest(
  601. '<?php
  602. class Foo
  603. {
  604. /* constant */ private const BAR = 3;
  605. /* variable */ private $bar;
  606. /* function */ private function bar() {}
  607. }',
  608. '<?php
  609. class Foo
  610. {
  611. private /* constant */ const BAR = 3;
  612. private /* variable */ $bar;
  613. private /* function */ function bar() {}
  614. }'
  615. );
  616. }
  617. public function testFixingWithAllKeywords(): void
  618. {
  619. $this->doTest(
  620. '<?php
  621. abstract class Foo
  622. {
  623. abstract protected static function fooA();
  624. abstract protected static function fooB();
  625. abstract protected static function fooC();
  626. abstract protected static function fooD();
  627. abstract protected static function fooE();
  628. abstract protected static function fooF();
  629. abstract public static function fooG();
  630. abstract public static function fooH();
  631. }
  632. ',
  633. '<?php
  634. abstract class Foo
  635. {
  636. abstract protected static function fooA();
  637. abstract static protected function fooB();
  638. protected abstract static function fooC();
  639. protected static abstract function fooD();
  640. static abstract protected function fooE();
  641. static protected abstract function fooF();
  642. abstract static function fooG();
  643. static abstract function fooH();
  644. }
  645. '
  646. );
  647. }
  648. /**
  649. * @dataProvider provideFixCases
  650. */
  651. public function testFix(string $expected, ?string $input = null): void
  652. {
  653. $this->doTest($expected, $input);
  654. }
  655. public static function provideFixCases(): iterable
  656. {
  657. yield [
  658. '<?php class Foo { private int $foo; }',
  659. ];
  660. yield [
  661. '<?php class Foo { protected ?string $foo; }',
  662. ];
  663. yield [
  664. '<?php class Foo { public ? string $foo; }',
  665. ];
  666. yield [
  667. '<?php class Foo { public ? string $foo; }',
  668. '<?php class Foo { var ? string $foo; }',
  669. ];
  670. yield [
  671. '<?php class Foo { public static Foo\Bar $foo; }',
  672. '<?php class Foo { static public Foo\Bar $foo; }',
  673. ];
  674. yield [
  675. '<?php class Foo { public array $foo; }',
  676. ];
  677. yield [
  678. '<?php class Foo { public ?array $foo; }',
  679. ];
  680. yield [
  681. '<?php class Foo { public static ?array $foo; }',
  682. '<?php class Foo { static public ?array $foo; }',
  683. ];
  684. }
  685. /**
  686. * @requires PHP 8.0
  687. *
  688. * @dataProvider provideFix80Cases
  689. */
  690. public function testFix80(string $expected, ?string $input = null): void
  691. {
  692. $this->doTest($expected, $input);
  693. }
  694. public static function provideFix80Cases(): iterable
  695. {
  696. yield [
  697. '<?php class Foo { private int|float|null $foo; }',
  698. ];
  699. yield [
  700. '<?php class Foo { private int | /* or empty */ null $foo; }',
  701. ];
  702. yield [
  703. '<?php class Foo { private array|null $foo; }',
  704. ];
  705. yield [
  706. '<?php class Foo { private null|array $foo; }',
  707. ];
  708. yield [
  709. '<?php class Foo { public static null|array $foo; }',
  710. '<?php class Foo { static null|array $foo; }',
  711. ];
  712. }
  713. /**
  714. * @dataProvider provideFix81Cases
  715. *
  716. * @requires PHP 8.1
  717. */
  718. public function testFix81(string $expected, ?string $input = null): void
  719. {
  720. $this->doTest($expected, $input);
  721. }
  722. public static function provideFix81Cases(): iterable
  723. {
  724. yield [
  725. '<?php class Foo { public Foo1&Bar $foo; }',
  726. ];
  727. yield [
  728. '<?php
  729. class Foo
  730. {
  731. public readonly string $prop2a;
  732. }
  733. ',
  734. '<?php
  735. class Foo
  736. {
  737. readonly public string $prop2a;
  738. }
  739. ',
  740. ];
  741. yield [
  742. '<?php
  743. class Foo
  744. {
  745. public readonly string $prop1;
  746. public readonly string $prop2;
  747. }
  748. ',
  749. '<?php
  750. class Foo
  751. {
  752. readonly string $prop1;
  753. public readonly string $prop2;
  754. }
  755. ',
  756. ];
  757. yield [
  758. '<?php
  759. class Foo
  760. {
  761. final public const B = "2";
  762. }
  763. ',
  764. '<?php
  765. class Foo
  766. {
  767. public final const B = "2";
  768. }
  769. ',
  770. ];
  771. yield [
  772. '<?php
  773. class Foo
  774. {
  775. final public const B = "2";
  776. }
  777. ',
  778. '<?php
  779. class Foo
  780. {
  781. final const B = "2";
  782. }
  783. ',
  784. ];
  785. yield [
  786. '<?php
  787. enum Foo {
  788. case CAT;
  789. public function test(): self { return $this; }
  790. }
  791. var_dump(Foo::CAT->test());',
  792. '<?php
  793. enum Foo {
  794. case CAT;
  795. function test(): self { return $this; }
  796. }
  797. var_dump(Foo::CAT->test());',
  798. ];
  799. }
  800. /**
  801. * @requires PHP 8.2
  802. *
  803. * @dataProvider provideFix82Cases
  804. */
  805. public function testFix82(string $expected, ?string $input = null): void
  806. {
  807. $this->doTest($expected, $input);
  808. }
  809. public static function provideFix82Cases(): iterable
  810. {
  811. yield [
  812. '<?php trait Foo { public const Bar = 1; }',
  813. '<?php trait Foo { const Bar = 1; }',
  814. ];
  815. yield [
  816. '<?php class Foo {
  817. public (A&B)|C|D $x;
  818. protected A|(B&C)|D $y;
  819. private A|B|(C&D) $z;
  820. }',
  821. ];
  822. }
  823. }