VisibilityRequiredFixerTest.php 19 KB

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