PhpdocAlignFixerTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  1. <?php
  2. /*
  3. * This file is part of PHP CS Fixer.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. namespace PhpCsFixer\Tests\Fixer\Phpdoc;
  12. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  13. use PhpCsFixer\WhitespacesFixerConfig;
  14. /**
  15. * @internal
  16. *
  17. * @covers \PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer
  18. */
  19. final class PhpdocAlignFixerTest extends AbstractFixerTestCase
  20. {
  21. public function testFix()
  22. {
  23. $this->fixer->configure(['tags' => ['param']]);
  24. $expected = <<<'EOF'
  25. <?php
  26. /**
  27. * @param EngineInterface $templating
  28. * @param string $format
  29. * @param int $code An HTTP response status code
  30. * @param bool $debug
  31. * @param mixed &$reference A parameter passed by reference
  32. */
  33. EOF;
  34. $input = <<<'EOF'
  35. <?php
  36. /**
  37. * @param EngineInterface $templating
  38. * @param string $format
  39. * @param int $code An HTTP response status code
  40. * @param bool $debug
  41. * @param mixed &$reference A parameter passed by reference
  42. */
  43. EOF;
  44. $this->doTest($expected, $input);
  45. }
  46. public function testFixMultiLineDesc()
  47. {
  48. $this->fixer->configure(['tags' => ['param', 'property', 'method']]);
  49. $expected = <<<'EOF'
  50. <?php
  51. /**
  52. * @param EngineInterface $templating
  53. * @param string $format
  54. * @param int $code An HTTP response status code
  55. * See constants
  56. * @param bool $debug
  57. * @param bool $debug See constants
  58. * See constants
  59. * @param mixed &$reference A parameter passed by reference
  60. * @property mixed $foo A foo
  61. * See constants
  62. * @method static baz($bop) A method that does a thing
  63. * It does it well
  64. */
  65. EOF;
  66. $input = <<<'EOF'
  67. <?php
  68. /**
  69. * @param EngineInterface $templating
  70. * @param string $format
  71. * @param int $code An HTTP response status code
  72. * See constants
  73. * @param bool $debug
  74. * @param bool $debug See constants
  75. * See constants
  76. * @param mixed &$reference A parameter passed by reference
  77. * @property mixed $foo A foo
  78. * See constants
  79. * @method static baz($bop) A method that does a thing
  80. * It does it well
  81. */
  82. EOF;
  83. $this->doTest($expected, $input);
  84. }
  85. public function testFixMultiLineDescWithThrows()
  86. {
  87. $this->fixer->configure(['tags' => ['param', 'return', 'throws']]);
  88. $expected = <<<'EOF'
  89. <?php
  90. /**
  91. * @param EngineInterface $templating
  92. * @param string $format
  93. * @param int $code An HTTP response status code
  94. * See constants
  95. * @param bool $debug
  96. * @param bool $debug See constants
  97. * See constants
  98. * @param mixed &$reference A parameter passed by reference
  99. *
  100. * @return Foo description foo
  101. *
  102. * @throws Foo description foo
  103. * description foo
  104. */
  105. EOF;
  106. $input = <<<'EOF'
  107. <?php
  108. /**
  109. * @param EngineInterface $templating
  110. * @param string $format
  111. * @param int $code An HTTP response status code
  112. * See constants
  113. * @param bool $debug
  114. * @param bool $debug See constants
  115. * See constants
  116. * @param mixed &$reference A parameter passed by reference
  117. *
  118. * @return Foo description foo
  119. *
  120. * @throws Foo description foo
  121. * description foo
  122. */
  123. EOF;
  124. $this->doTest($expected, $input);
  125. }
  126. public function testFixWithReturnAndThrows()
  127. {
  128. $this->fixer->configure(['tags' => ['param', 'throws', 'return']]);
  129. $expected = <<<'EOF'
  130. <?php
  131. /**
  132. * @param EngineInterface $templating
  133. * @param mixed &$reference A parameter passed by reference
  134. * @throws Bar description bar
  135. * @return Foo description foo
  136. */
  137. EOF;
  138. $input = <<<'EOF'
  139. <?php
  140. /**
  141. * @param EngineInterface $templating
  142. * @param mixed &$reference A parameter passed by reference
  143. * @throws Bar description bar
  144. * @return Foo description foo
  145. */
  146. EOF;
  147. $this->doTest($expected, $input);
  148. }
  149. /**
  150. * References the issue #55 on github issue
  151. * https://github.com/FriendsOfPhp/PHP-CS-Fixer/issues/55.
  152. */
  153. public function testFixThreeParamsWithReturn()
  154. {
  155. $this->fixer->configure(['tags' => ['param', 'return']]);
  156. $expected = <<<'EOF'
  157. <?php
  158. /**
  159. * @param string $param1
  160. * @param bool $param2 lorem ipsum
  161. * @param string $param3 lorem ipsum
  162. * @return int lorem ipsum
  163. */
  164. EOF;
  165. $input = <<<'EOF'
  166. <?php
  167. /**
  168. * @param string $param1
  169. * @param bool $param2 lorem ipsum
  170. * @param string $param3 lorem ipsum
  171. * @return int lorem ipsum
  172. */
  173. EOF;
  174. $this->doTest($expected, $input);
  175. }
  176. public function testFixOnlyReturn()
  177. {
  178. $this->fixer->configure(['tags' => ['return']]);
  179. $expected = <<<'EOF'
  180. <?php
  181. /**
  182. * @return Foo description foo
  183. */
  184. EOF;
  185. $input = <<<'EOF'
  186. <?php
  187. /**
  188. * @return Foo description foo
  189. */
  190. EOF;
  191. $this->doTest($expected, $input);
  192. }
  193. public function testReturnWithDollarThis()
  194. {
  195. $this->fixer->configure(['tags' => ['param', 'return']]);
  196. $expected = <<<'EOF'
  197. <?php
  198. /**
  199. * @param Foo $foo
  200. * @return $this
  201. */
  202. EOF;
  203. $input = <<<'EOF'
  204. <?php
  205. /**
  206. * @param Foo $foo
  207. * @return $this
  208. */
  209. EOF;
  210. $this->doTest($expected, $input);
  211. }
  212. public function testCustomAnnotationsStayUntouched()
  213. {
  214. $this->fixer->configure(['tags' => ['return']]);
  215. $expected = <<<'EOF'
  216. <?php
  217. /**
  218. * @return string
  219. * @SuppressWarnings(PHPMD.UnusedLocalVariable)
  220. */
  221. EOF;
  222. $input = <<<'EOF'
  223. <?php
  224. /**
  225. * @return string
  226. * @SuppressWarnings(PHPMD.UnusedLocalVariable)
  227. */
  228. EOF;
  229. $this->doTest($expected, $input);
  230. }
  231. public function testCustomAnnotationsStayUntouched2()
  232. {
  233. $this->fixer->configure(['tags' => ['var']]);
  234. $expected = <<<'EOF'
  235. <?php
  236. class X
  237. {
  238. /**
  239. * @var Collection<Value>|Value[]
  240. * @ORM\ManyToMany(
  241. * targetEntity="\Dl\Component\DomainModel\Product\Value\AbstractValue",
  242. * inversedBy="externalAliases"
  243. * )
  244. */
  245. private $values;
  246. }
  247. EOF;
  248. $this->doTest($expected);
  249. }
  250. public function testFixWithVar()
  251. {
  252. $this->fixer->configure(['tags' => ['var']]);
  253. $expected = <<<'EOF'
  254. <?php
  255. /**
  256. * @var Type
  257. */
  258. EOF;
  259. $input = <<<'EOF'
  260. <?php
  261. /**
  262. * @var Type
  263. */
  264. EOF;
  265. $this->doTest($expected, $input);
  266. }
  267. public function testFixWithType()
  268. {
  269. $this->fixer->configure(['tags' => ['type']]);
  270. $expected = <<<'EOF'
  271. <?php
  272. /**
  273. * @type Type
  274. */
  275. EOF;
  276. $input = <<<'EOF'
  277. <?php
  278. /**
  279. * @type Type
  280. */
  281. EOF;
  282. $this->doTest($expected, $input);
  283. }
  284. public function testFixWithVarAndDescription()
  285. {
  286. $this->fixer->configure(['tags' => ['var']]);
  287. $expected = <<<'EOF'
  288. <?php
  289. /**
  290. * This is a variable.
  291. *
  292. * @var Type
  293. */
  294. EOF;
  295. $input = <<<'EOF'
  296. <?php
  297. /**
  298. * This is a variable.
  299. *
  300. * @var Type
  301. */
  302. EOF;
  303. $this->doTest($expected, $input);
  304. }
  305. public function testFixWithVarAndInlineDescription()
  306. {
  307. $this->fixer->configure(['tags' => ['var']]);
  308. $expected = <<<'EOF'
  309. <?php
  310. /**
  311. * @var Type This is a variable.
  312. */
  313. EOF;
  314. $input = <<<'EOF'
  315. <?php
  316. /**
  317. * @var Type This is a variable.
  318. */
  319. EOF;
  320. $this->doTest($expected, $input);
  321. }
  322. public function testFixWithTypeAndInlineDescription()
  323. {
  324. $this->fixer->configure(['tags' => ['type']]);
  325. $expected = <<<'EOF'
  326. <?php
  327. /**
  328. * @type Type This is a variable.
  329. */
  330. EOF;
  331. $input = <<<'EOF'
  332. <?php
  333. /**
  334. * @type Type This is a variable.
  335. */
  336. EOF;
  337. $this->doTest($expected, $input);
  338. }
  339. public function testRetainsNewLineCharacters()
  340. {
  341. $this->fixer->configure(['tags' => ['param']]);
  342. // when we're not modifying a docblock, then line endings shouldn't change
  343. $this->doTest("<?php\r /**\r * @param Example Hello there!\r */\r");
  344. }
  345. public function testMalformedDocBlock()
  346. {
  347. $this->fixer->configure(['tags' => ['return']]);
  348. $input = <<<'EOF'
  349. <?php
  350. /**
  351. * @return string
  352. * */
  353. EOF;
  354. $this->doTest($input);
  355. }
  356. public function testDifferentIndentation()
  357. {
  358. $this->fixer->configure(['tags' => ['param', 'return']]);
  359. $expected = <<<'EOF'
  360. <?php
  361. /**
  362. * @param int $limit
  363. * @param string $more
  364. *
  365. * @return array
  366. */
  367. /**
  368. * @param int $limit
  369. * @param string $more
  370. *
  371. * @return array
  372. */
  373. EOF;
  374. $input = <<<'EOF'
  375. <?php
  376. /**
  377. * @param int $limit
  378. * @param string $more
  379. *
  380. * @return array
  381. */
  382. /**
  383. * @param int $limit
  384. * @param string $more
  385. *
  386. * @return array
  387. */
  388. EOF;
  389. $this->doTest($expected, $input);
  390. }
  391. /**
  392. * @param array $config
  393. * @param string $expected
  394. * @param null|string $input
  395. *
  396. * @dataProvider provideMessyWhitespacesCases
  397. */
  398. public function testMessyWhitespaces(array $config, $expected, $input = null)
  399. {
  400. $this->fixer->configure($config);
  401. $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n"));
  402. $this->doTest($expected, $input);
  403. }
  404. public function provideMessyWhitespacesCases()
  405. {
  406. return [
  407. [
  408. ['tags' => ['type']],
  409. "<?php\r\n\t/**\r\n\t * @type Type This is a variable.\r\n\t */",
  410. "<?php\r\n\t/**\r\n\t * @type Type This is a variable.\r\n\t */",
  411. ],
  412. [
  413. ['tags' => ['param', 'return']],
  414. "<?php\r\n/**\r\n * @param int \$limit\r\n * @param string \$more\r\n *\r\n * @return array\r\n */",
  415. "<?php\r\n/**\r\n * @param int \$limit\r\n * @param string \$more\r\n *\r\n * @return array\r\n */",
  416. ],
  417. ];
  418. }
  419. public function testCanFixBadFormatted()
  420. {
  421. $this->fixer->configure(['tags' => ['var']]);
  422. $expected = "<?php\n /**\n * @var Foo */\n";
  423. $this->doTest($expected);
  424. }
  425. public function testFixUnicode()
  426. {
  427. $this->fixer->configure(['tags' => ['param', 'return']]);
  428. $expected = <<<'EOF'
  429. <?php
  430. /**
  431. * Method test.
  432. *
  433. * @param int $foobar Description
  434. * @param string $foo Description
  435. * @param mixed $bar Description word_with_ą
  436. * @param int|null $test Description
  437. */
  438. $a = 1;
  439. /**
  440. * @return string
  441. * @SuppressWarnings(PHPMD.UnusedLocalVariable) word_with_ą
  442. */
  443. $b = 1;
  444. EOF;
  445. $input = <<<'EOF'
  446. <?php
  447. /**
  448. * Method test.
  449. *
  450. * @param int $foobar Description
  451. * @param string $foo Description
  452. * @param mixed $bar Description word_with_ą
  453. * @param int|null $test Description
  454. */
  455. $a = 1;
  456. /**
  457. * @return string
  458. * @SuppressWarnings(PHPMD.UnusedLocalVariable) word_with_ą
  459. */
  460. $b = 1;
  461. EOF;
  462. $this->doTest($expected, $input);
  463. }
  464. public function testDoesNotAlignPropertyByDefault()
  465. {
  466. $expected = <<<'EOF'
  467. <?php
  468. /**
  469. * @param int $foobar Description
  470. * @return int
  471. * @throws Exception
  472. * @var FooBar
  473. * @type BarFoo
  474. * @property string $foo Hello World
  475. */
  476. EOF;
  477. $input = <<<'EOF'
  478. <?php
  479. /**
  480. * @param int $foobar Description
  481. * @return int
  482. * @throws Exception
  483. * @var FooBar
  484. * @type BarFoo
  485. * @property string $foo Hello World
  486. */
  487. EOF;
  488. $this->doTest($expected, $input);
  489. }
  490. public function testAlignsProperty()
  491. {
  492. $this->fixer->configure(['tags' => ['param', 'property', 'return', 'throws', 'type', 'var']]);
  493. $expected = <<<'EOF'
  494. <?php
  495. /**
  496. * @param int $foobar Description
  497. * @return int
  498. * @throws Exception
  499. * @var FooBar
  500. * @type BarFoo
  501. * @property string $foo Hello World
  502. */
  503. EOF;
  504. $input = <<<'EOF'
  505. <?php
  506. /**
  507. * @param int $foobar Description
  508. * @return int
  509. * @throws Exception
  510. * @var FooBar
  511. * @type BarFoo
  512. * @property string $foo Hello World
  513. */
  514. EOF;
  515. $this->doTest($expected, $input);
  516. }
  517. public function testDoesNotAlignMethodByDefault()
  518. {
  519. $expected = <<<'EOF'
  520. <?php
  521. /**
  522. * @param int $foobar Description
  523. * @return int
  524. * @throws Exception
  525. * @var FooBar
  526. * @type BarFoo
  527. * @method string foo(string $bar) Hello World
  528. */
  529. EOF;
  530. $input = <<<'EOF'
  531. <?php
  532. /**
  533. * @param int $foobar Description
  534. * @return int
  535. * @throws Exception
  536. * @var FooBar
  537. * @type BarFoo
  538. * @method string foo(string $bar) Hello World
  539. */
  540. EOF;
  541. $this->doTest($expected, $input);
  542. }
  543. public function testAlignsMethod()
  544. {
  545. $this->fixer->configure(['tags' => ['param', 'method', 'return', 'throws', 'type', 'var']]);
  546. $expected = <<<'EOF'
  547. <?php
  548. /**
  549. * @param int $foobar Description
  550. * @return int
  551. * @throws Exception
  552. * @var FooBar
  553. * @type BarFoo
  554. * @method int foo(string $bar, string ...$things, int &$baz) Description
  555. */
  556. EOF;
  557. $input = <<<'EOF'
  558. <?php
  559. /**
  560. * @param int $foobar Description
  561. * @return int
  562. * @throws Exception
  563. * @var FooBar
  564. * @type BarFoo
  565. * @method int foo(string $bar, string ...$things, int &$baz) Description
  566. */
  567. EOF;
  568. $this->doTest($expected, $input);
  569. }
  570. public function testAlignsMethodWithoutParameters()
  571. {
  572. $this->fixer->configure(['tags' => ['method', 'property']]);
  573. $expected = <<<'EOF'
  574. <?php
  575. /**
  576. * @property string $foo Desc
  577. * @method int foo() Description
  578. */
  579. EOF;
  580. $input = <<<'EOF'
  581. <?php
  582. /**
  583. * @property string $foo Desc
  584. * @method int foo() Description
  585. */
  586. EOF;
  587. $this->doTest($expected, $input);
  588. }
  589. public function testDoesNotFormatMethod()
  590. {
  591. $this->fixer->configure(['tags' => ['method']]);
  592. $input = <<<'EOF'
  593. <?php
  594. /**
  595. * @method int foo( string $bar ) Description
  596. */
  597. EOF;
  598. $this->doTest($input);
  599. }
  600. public function testAlignsMethodWithoutReturnType()
  601. {
  602. $this->fixer->configure(['tags' => ['method', 'property']]);
  603. $expected = <<<'EOF'
  604. <?php
  605. /**
  606. * @property string $foo Desc
  607. * @method int foo() Description
  608. * @method bar() Descrip
  609. */
  610. EOF;
  611. $input = <<<'EOF'
  612. <?php
  613. /**
  614. * @property string $foo Desc
  615. * @method int foo() Description
  616. * @method bar() Descrip
  617. */
  618. EOF;
  619. $this->doTest($expected, $input);
  620. }
  621. public function testAlignsMethodsWithoutReturnType()
  622. {
  623. $this->fixer->configure(['tags' => ['method']]);
  624. $expected = <<<'EOF'
  625. <?php
  626. /**
  627. * @method fooBaz() Description
  628. * @method bar(string $foo) Descrip
  629. */
  630. EOF;
  631. $input = <<<'EOF'
  632. <?php
  633. /**
  634. * @method fooBaz() Description
  635. * @method bar(string $foo) Descrip
  636. */
  637. EOF;
  638. $this->doTest($expected, $input);
  639. }
  640. public function testDoesNotAlignWithEmptyConfig()
  641. {
  642. $this->fixer->configure(['tags' => []]);
  643. $input = <<<'EOF'
  644. <?php
  645. /**
  646. * @param int $foobar Description
  647. * @return int
  648. * @throws Exception
  649. * @var FooBar
  650. * @type BarFoo
  651. * @property string $foo Hello World
  652. * @method int bar() Description
  653. */
  654. EOF;
  655. $this->doTest($input);
  656. }
  657. /**
  658. * @param array $config
  659. * @param string $expected
  660. * @param string $input
  661. *
  662. *
  663. * @dataProvider provideVariadicCases
  664. */
  665. public function testVariadicParams(array $config, $expected, $input)
  666. {
  667. $this->fixer->configure($config);
  668. $this->doTest($expected, $input);
  669. }
  670. public function provideVariadicCases()
  671. {
  672. return [
  673. [
  674. ['tags' => ['param']],
  675. '<?php
  676. final class Sample
  677. {
  678. /**
  679. * @param int[] $a A
  680. * @param int &$b B
  681. * @param array ...$c C
  682. */
  683. public function sample2($a, &$b, ...$c)
  684. {
  685. }
  686. }
  687. ',
  688. '<?php
  689. final class Sample
  690. {
  691. /**
  692. * @param int[] $a A
  693. * @param int &$b B
  694. * @param array ...$c C
  695. */
  696. public function sample2($a, &$b, ...$c)
  697. {
  698. }
  699. }
  700. ',
  701. ],
  702. [
  703. ['tags' => ['param']],
  704. '<?php
  705. final class Sample
  706. {
  707. /**
  708. * @param int $a
  709. * @param int $b
  710. * @param array[] ...$c
  711. */
  712. public function sample2($a, $b, ...$c)
  713. {
  714. }
  715. }
  716. ',
  717. '<?php
  718. final class Sample
  719. {
  720. /**
  721. * @param int $a
  722. * @param int $b
  723. * @param array[] ...$c
  724. */
  725. public function sample2($a, $b, ...$c)
  726. {
  727. }
  728. }
  729. ',
  730. ],
  731. ];
  732. }
  733. /**
  734. * @param array $config
  735. * @param string $input
  736. *
  737. * @dataProvider provideInvalidPhpdocCases
  738. */
  739. public function testInvalidPhpdocsAreUnchanged(array $config, $input)
  740. {
  741. $this->fixer->configure($config);
  742. $this->doTest($input);
  743. }
  744. public function provideInvalidPhpdocCases()
  745. {
  746. return [
  747. [
  748. ['tags' => ['param', 'return', 'throws', 'type', 'var']],
  749. '<?php
  750. /**
  751. * @ Security("is_granted(\'CANCEL\', giftCard)")
  752. */
  753. ',
  754. ],
  755. [
  756. ['tags' => ['param', 'return', 'throws', 'type', 'var', 'method']],
  757. '<?php
  758. /**
  759. * @ Security("is_granted(\'CANCEL\', giftCard)")
  760. */
  761. ',
  762. ],
  763. [
  764. ['tags' => ['param', 'return', 'throws', 'type', 'var']],
  765. '<?php
  766. /**
  767. * @ Security("is_granted(\'CANCEL\', giftCard)")
  768. * @ foo bar
  769. * @ foo
  770. */
  771. ',
  772. ],
  773. ];
  774. }
  775. }