PhpdocAlignFixerTest.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542
  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\Phpdoc;
  13. use PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer;
  14. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  15. use PhpCsFixer\WhitespacesFixerConfig;
  16. /**
  17. * @internal
  18. *
  19. * @covers \PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer
  20. */
  21. final class PhpdocAlignFixerTest extends AbstractFixerTestCase
  22. {
  23. public function testFix(): void
  24. {
  25. $this->fixer->configure(['tags' => ['param']]);
  26. $expected = <<<'EOF'
  27. <?php
  28. /**
  29. * @param EngineInterface $templating
  30. * @param string $format
  31. * @param int $code An HTTP response status code
  32. * @param bool $debug
  33. * @param mixed &$reference A parameter passed by reference
  34. */
  35. EOF;
  36. $input = <<<'EOF'
  37. <?php
  38. /**
  39. * @param EngineInterface $templating
  40. * @param string $format
  41. * @param int $code An HTTP response status code
  42. * @param bool $debug
  43. * @param mixed &$reference A parameter passed by reference
  44. */
  45. EOF;
  46. $this->doTest($expected, $input);
  47. }
  48. public function testFixLeftAlign(): void
  49. {
  50. $this->fixer->configure(['tags' => ['param'], 'align' => PhpdocAlignFixer::ALIGN_LEFT]);
  51. $expected = <<<'EOF'
  52. <?php
  53. /**
  54. * @param EngineInterface $templating
  55. * @param string $format
  56. * @param int $code An HTTP response status code
  57. * @param bool $debug
  58. * @param mixed &$reference A parameter passed by reference
  59. */
  60. EOF;
  61. $input = <<<'EOF'
  62. <?php
  63. /**
  64. * @param EngineInterface $templating
  65. * @param string $format
  66. * @param int $code An HTTP response status code
  67. * @param bool $debug
  68. * @param mixed &$reference A parameter passed by reference
  69. */
  70. EOF;
  71. $this->doTest($expected, $input);
  72. }
  73. public function testFixPartiallyUntyped(): void
  74. {
  75. $this->fixer->configure(['tags' => ['param']]);
  76. $expected = <<<'EOF'
  77. <?php
  78. /**
  79. * @param $id
  80. * @param $parentId
  81. * @param int $websiteId
  82. * @param $position
  83. * @param int[][] $siblings
  84. */
  85. EOF;
  86. $input = <<<'EOF'
  87. <?php
  88. /**
  89. * @param $id
  90. * @param $parentId
  91. * @param int $websiteId
  92. * @param $position
  93. * @param int[][] $siblings
  94. */
  95. EOF;
  96. $this->doTest($expected, $input);
  97. }
  98. public function testFixPartiallyUntypedLeftAlign(): void
  99. {
  100. $this->fixer->configure(['tags' => ['param'], 'align' => PhpdocAlignFixer::ALIGN_LEFT]);
  101. $expected = <<<'EOF'
  102. <?php
  103. /**
  104. * @param $id
  105. * @param $parentId
  106. * @param int $websiteId
  107. * @param $position
  108. * @param int[][] $siblings
  109. */
  110. EOF;
  111. $input = <<<'EOF'
  112. <?php
  113. /**
  114. * @param $id
  115. * @param $parentId
  116. * @param int $websiteId
  117. * @param $position
  118. * @param int[][] $siblings
  119. */
  120. EOF;
  121. $this->doTest($expected, $input);
  122. }
  123. public function testFixMultiLineDesc(): void
  124. {
  125. $this->fixer->configure(['tags' => ['param', 'property', 'method']]);
  126. $expected = <<<'EOF'
  127. <?php
  128. /**
  129. * @param EngineInterface $templating
  130. * @param string $format
  131. * @param int $code An HTTP response status code
  132. * See constants
  133. * @param bool $debug
  134. * @param bool $debug See constants
  135. * See constants
  136. * @param mixed &$reference A parameter passed by reference
  137. * @property mixed $foo A foo
  138. * See constants
  139. * @method static baz($bop) A method that does a thing
  140. * It does it well
  141. */
  142. EOF;
  143. $input = <<<'EOF'
  144. <?php
  145. /**
  146. * @param EngineInterface $templating
  147. * @param string $format
  148. * @param int $code An HTTP response status code
  149. * See constants
  150. * @param bool $debug
  151. * @param bool $debug See constants
  152. * See constants
  153. * @param mixed &$reference A parameter passed by reference
  154. * @property mixed $foo A foo
  155. * See constants
  156. * @method static baz($bop) A method that does a thing
  157. * It does it well
  158. */
  159. EOF;
  160. $this->doTest($expected, $input);
  161. }
  162. public function testFixMultiLineDescLeftAlign(): void
  163. {
  164. $this->fixer->configure(['tags' => ['param', 'property', 'method'], 'align' => PhpdocAlignFixer::ALIGN_LEFT]);
  165. $expected = <<<'EOF'
  166. <?php
  167. /**
  168. * @param EngineInterface $templating
  169. * @param string $format
  170. * @param int $code An HTTP response status code
  171. * See constants
  172. * @param bool $debug
  173. * @param bool $debug See constants
  174. * See constants
  175. * @param mixed &$reference A parameter passed by reference
  176. * @property mixed $foo A foo
  177. * See constants
  178. * @method static baz($bop) A method that does a thing
  179. * It does it well
  180. */
  181. EOF;
  182. $input = <<<'EOF'
  183. <?php
  184. /**
  185. * @param EngineInterface $templating
  186. * @param string $format
  187. * @param int $code An HTTP response status code
  188. * See constants
  189. * @param bool $debug
  190. * @param bool $debug See constants
  191. * See constants
  192. * @param mixed &$reference A parameter passed by reference
  193. * @property mixed $foo A foo
  194. * See constants
  195. * @method static baz($bop) A method that does a thing
  196. * It does it well
  197. */
  198. EOF;
  199. $this->doTest($expected, $input);
  200. }
  201. public function testFixMultiLineDescWithThrows(): void
  202. {
  203. $this->fixer->configure(['tags' => ['param', 'return', 'throws']]);
  204. $expected = <<<'EOF'
  205. <?php
  206. /**
  207. * @param EngineInterface $templating
  208. * @param string $format
  209. * @param int $code An HTTP response status code
  210. * See constants
  211. * @param bool $debug
  212. * @param bool $debug See constants
  213. * See constants
  214. * @param mixed &$reference A parameter passed by reference
  215. *
  216. * @return Foo description foo
  217. *
  218. * @throws Foo description foo
  219. * description foo
  220. */
  221. EOF;
  222. $input = <<<'EOF'
  223. <?php
  224. /**
  225. * @param EngineInterface $templating
  226. * @param string $format
  227. * @param int $code An HTTP response status code
  228. * See constants
  229. * @param bool $debug
  230. * @param bool $debug See constants
  231. * See constants
  232. * @param mixed &$reference A parameter passed by reference
  233. *
  234. * @return Foo description foo
  235. *
  236. * @throws Foo description foo
  237. * description foo
  238. */
  239. EOF;
  240. $this->doTest($expected, $input);
  241. }
  242. public function testFixMultiLineDescWithThrowsLeftAlign(): void
  243. {
  244. $this->fixer->configure(['tags' => ['param', 'return', 'throws'], 'align' => PhpdocAlignFixer::ALIGN_LEFT]);
  245. $expected = <<<'EOF'
  246. <?php
  247. /**
  248. * @param EngineInterface $templating
  249. * @param string $format
  250. * @param int $code An HTTP response status code
  251. * See constants
  252. * @param bool $debug
  253. * @param bool $debug See constants
  254. * See constants
  255. * @param mixed &$reference A parameter passed by reference
  256. *
  257. * @return Foo description foo
  258. *
  259. * @throws Foo description foo
  260. * description foo
  261. */
  262. EOF;
  263. $input = <<<'EOF'
  264. <?php
  265. /**
  266. * @param EngineInterface $templating
  267. * @param string $format
  268. * @param int $code An HTTP response status code
  269. * See constants
  270. * @param bool $debug
  271. * @param bool $debug See constants
  272. * See constants
  273. * @param mixed &$reference A parameter passed by reference
  274. *
  275. * @return Foo description foo
  276. *
  277. * @throws Foo description foo
  278. * description foo
  279. */
  280. EOF;
  281. $this->doTest($expected, $input);
  282. }
  283. public function testFixWithReturnAndThrows(): void
  284. {
  285. $this->fixer->configure(['tags' => ['param', 'throws', 'return']]);
  286. $expected = <<<'EOF'
  287. <?php
  288. /**
  289. * @param EngineInterface $templating
  290. * @param mixed &$reference A parameter passed by reference
  291. * @throws Bar description bar
  292. * @return Foo description foo
  293. */
  294. EOF;
  295. $input = <<<'EOF'
  296. <?php
  297. /**
  298. * @param EngineInterface $templating
  299. * @param mixed &$reference A parameter passed by reference
  300. * @throws Bar description bar
  301. * @return Foo description foo
  302. */
  303. EOF;
  304. $this->doTest($expected, $input);
  305. }
  306. /**
  307. * References the issue #55 on github issue
  308. * https://github.com/FriendsOfPhp/PHP-CS-Fixer/issues/55.
  309. */
  310. public function testFixThreeParamsWithReturn(): void
  311. {
  312. $this->fixer->configure(['tags' => ['param', 'return']]);
  313. $expected = <<<'EOF'
  314. <?php
  315. /**
  316. * @param string $param1
  317. * @param bool $param2 lorem ipsum
  318. * @param string $param3 lorem ipsum
  319. * @return int lorem ipsum
  320. */
  321. EOF;
  322. $input = <<<'EOF'
  323. <?php
  324. /**
  325. * @param string $param1
  326. * @param bool $param2 lorem ipsum
  327. * @param string $param3 lorem ipsum
  328. * @return int lorem ipsum
  329. */
  330. EOF;
  331. $this->doTest($expected, $input);
  332. }
  333. public function testFixOnlyReturn(): void
  334. {
  335. $this->fixer->configure(['tags' => ['return']]);
  336. $expected = <<<'EOF'
  337. <?php
  338. /**
  339. * @return Foo description foo
  340. */
  341. EOF;
  342. $input = <<<'EOF'
  343. <?php
  344. /**
  345. * @return Foo description foo
  346. */
  347. EOF;
  348. $this->doTest($expected, $input);
  349. }
  350. public function testReturnWithDollarThis(): void
  351. {
  352. $this->fixer->configure(['tags' => ['param', 'return']]);
  353. $expected = <<<'EOF'
  354. <?php
  355. /**
  356. * @param Foo $foo
  357. * @return $this
  358. */
  359. EOF;
  360. $input = <<<'EOF'
  361. <?php
  362. /**
  363. * @param Foo $foo
  364. * @return $this
  365. */
  366. EOF;
  367. $this->doTest($expected, $input);
  368. }
  369. public function testCustomAnnotationsStayUntouched(): void
  370. {
  371. $this->fixer->configure(['tags' => ['return']]);
  372. $expected = <<<'EOF'
  373. <?php
  374. /**
  375. * @return string
  376. * @SuppressWarnings(PHPMD.UnusedLocalVariable)
  377. */
  378. EOF;
  379. $input = <<<'EOF'
  380. <?php
  381. /**
  382. * @return string
  383. * @SuppressWarnings(PHPMD.UnusedLocalVariable)
  384. */
  385. EOF;
  386. $this->doTest($expected, $input);
  387. }
  388. public function testCustomAnnotationsStayUntouched2(): void
  389. {
  390. $this->fixer->configure(['tags' => ['var']]);
  391. $expected = <<<'EOF'
  392. <?php
  393. class X
  394. {
  395. /**
  396. * @var Collection<Value>|Value[]
  397. * @ORM\ManyToMany(
  398. * targetEntity="\Dl\Component\DomainModel\Product\Value\AbstractValue",
  399. * inversedBy="externalAliases"
  400. * )
  401. */
  402. private $values;
  403. }
  404. EOF;
  405. $this->doTest($expected);
  406. }
  407. public function testFixTestLeftAlign(): void
  408. {
  409. $this->fixer->configure(['tags' => ['param'], 'align' => PhpdocAlignFixer::ALIGN_LEFT]);
  410. $expected = <<<'EOF'
  411. <?php
  412. /**
  413. * @param int $a
  414. * @param string $b
  415. *
  416. * @dataProvider dataJobCreation
  417. */
  418. EOF;
  419. $input = <<<'EOF'
  420. <?php
  421. /**
  422. * @param int $a
  423. * @param string $b
  424. *
  425. * @dataProvider dataJobCreation
  426. */
  427. EOF;
  428. $this->doTest($expected, $input);
  429. }
  430. public function testFixTest(): void
  431. {
  432. $this->fixer->configure(['tags' => ['param']]);
  433. $expected = <<<'EOF'
  434. <?php
  435. /**
  436. * @param int $a
  437. * @param string|null $b
  438. *
  439. * @dataProvider dataJobCreation
  440. */
  441. EOF;
  442. $input = <<<'EOF'
  443. <?php
  444. /**
  445. * @param int $a
  446. * @param string|null $b
  447. *
  448. * @dataProvider dataJobCreation
  449. */
  450. EOF;
  451. $this->doTest($expected, $input);
  452. }
  453. public function testFixWithVar(): void
  454. {
  455. $this->fixer->configure(['tags' => ['var']]);
  456. $expected = <<<'EOF'
  457. <?php
  458. /**
  459. * @var Type
  460. */
  461. EOF;
  462. $input = <<<'EOF'
  463. <?php
  464. /**
  465. * @var Type
  466. */
  467. EOF;
  468. $this->doTest($expected, $input);
  469. }
  470. public function testFixWithType(): void
  471. {
  472. $this->fixer->configure(['tags' => ['type']]);
  473. $expected = <<<'EOF'
  474. <?php
  475. /**
  476. * @type Type
  477. */
  478. EOF;
  479. $input = <<<'EOF'
  480. <?php
  481. /**
  482. * @type Type
  483. */
  484. EOF;
  485. $this->doTest($expected, $input);
  486. }
  487. public function testFixWithVarAndDescription(): void
  488. {
  489. $this->fixer->configure(['tags' => ['var']]);
  490. $expected = <<<'EOF'
  491. <?php
  492. /**
  493. * This is a variable.
  494. *
  495. * @var Type
  496. */
  497. EOF;
  498. $input = <<<'EOF'
  499. <?php
  500. /**
  501. * This is a variable.
  502. *
  503. * @var Type
  504. */
  505. EOF;
  506. $this->doTest($expected, $input);
  507. }
  508. public function testFixWithVarAndInlineDescription(): void
  509. {
  510. $this->fixer->configure(['tags' => ['var']]);
  511. $expected = <<<'EOF'
  512. <?php
  513. /**
  514. * @var Type This is a variable.
  515. */
  516. EOF;
  517. $input = <<<'EOF'
  518. <?php
  519. /**
  520. * @var Type This is a variable.
  521. */
  522. EOF;
  523. $this->doTest($expected, $input);
  524. }
  525. public function testFixWithTypeAndInlineDescription(): void
  526. {
  527. $this->fixer->configure(['tags' => ['type']]);
  528. $expected = <<<'EOF'
  529. <?php
  530. /**
  531. * @type Type This is a variable.
  532. */
  533. EOF;
  534. $input = <<<'EOF'
  535. <?php
  536. /**
  537. * @type Type This is a variable.
  538. */
  539. EOF;
  540. $this->doTest($expected, $input);
  541. }
  542. public function testRetainsNewLineCharacters(): void
  543. {
  544. $this->fixer->configure(['tags' => ['param']]);
  545. // when we're not modifying a docblock, then line endings shouldn't change
  546. $this->doTest("<?php\r /**\r * @param Example Hello there!\r */\r");
  547. }
  548. public function testMalformedDocBlock(): void
  549. {
  550. $this->fixer->configure(['tags' => ['return']]);
  551. $input = <<<'EOF'
  552. <?php
  553. /**
  554. * @return string
  555. * */
  556. EOF;
  557. $this->doTest($input);
  558. }
  559. public function testDifferentIndentation(): void
  560. {
  561. $this->fixer->configure(['tags' => ['param', 'return']]);
  562. $expected = <<<'EOF'
  563. <?php
  564. /**
  565. * @param int $limit
  566. * @param string $more
  567. *
  568. * @return array
  569. */
  570. /**
  571. * @param int $limit
  572. * @param string $more
  573. *
  574. * @return array
  575. */
  576. EOF;
  577. $input = <<<'EOF'
  578. <?php
  579. /**
  580. * @param int $limit
  581. * @param string $more
  582. *
  583. * @return array
  584. */
  585. /**
  586. * @param int $limit
  587. * @param string $more
  588. *
  589. * @return array
  590. */
  591. EOF;
  592. $this->doTest($expected, $input);
  593. }
  594. public function testDifferentIndentationLeftAlign(): void
  595. {
  596. $this->fixer->configure(['tags' => ['param', 'return'], 'align' => PhpdocAlignFixer::ALIGN_LEFT]);
  597. $expected = <<<'EOF'
  598. <?php
  599. /**
  600. * @param int $limit
  601. * @param string $more
  602. *
  603. * @return array
  604. */
  605. /**
  606. * @param int $limit
  607. * @param string $more
  608. *
  609. * @return array
  610. */
  611. EOF;
  612. $input = <<<'EOF'
  613. <?php
  614. /**
  615. * @param int $limit
  616. * @param string $more
  617. *
  618. * @return array
  619. */
  620. /**
  621. * @param int $limit
  622. * @param string $more
  623. *
  624. * @return array
  625. */
  626. EOF;
  627. $this->doTest($expected, $input);
  628. }
  629. /**
  630. * @param array<string, mixed> $config
  631. *
  632. * @dataProvider provideMessyWhitespacesCases
  633. */
  634. public function testMessyWhitespaces(array $config, string $expected, string $input, WhitespacesFixerConfig $whitespacesFixerConfig): void
  635. {
  636. $this->fixer->configure($config);
  637. $this->fixer->setWhitespacesConfig($whitespacesFixerConfig);
  638. $this->doTest($expected, $input);
  639. }
  640. public static function provideMessyWhitespacesCases(): array
  641. {
  642. return [
  643. [
  644. ['tags' => ['type']],
  645. "<?php\r\n\t/**\r\n\t * @type Type This is a variable.\r\n\t */",
  646. "<?php\r\n\t/**\r\n\t * @type Type This is a variable.\r\n\t */",
  647. new WhitespacesFixerConfig("\t", "\r\n"),
  648. ],
  649. [
  650. ['tags' => ['param', 'return']],
  651. "<?php\r\n/**\r\n * @param int \$limit\r\n * @param string \$more\r\n *\r\n * @return array\r\n */",
  652. "<?php\r\n/**\r\n * @param int \$limit\r\n * @param string \$more\r\n *\r\n * @return array\r\n */",
  653. new WhitespacesFixerConfig("\t", "\r\n"),
  654. ],
  655. [
  656. [],
  657. "<?php\r\n/**\r\n * @param int \$limit\r\n * @param string \$more\r\n *\r\n * @return array\r\n */",
  658. "<?php\r\n/**\r\n * @param int \$limit\r\n * @param string \$more\r\n *\r\n * @return array\r\n */",
  659. new WhitespacesFixerConfig("\t", "\r\n"),
  660. ],
  661. [
  662. [],
  663. "<?php\n/**\n * @param int \$a\n * @param int \$b\n * ABC\n */",
  664. "<?php\n/**\n * @param int \$a\n * @param int \$b\n * ABC\n */",
  665. new WhitespacesFixerConfig(' ', "\n"),
  666. ],
  667. [
  668. [],
  669. "<?php\r\n/**\r\n * @param int \$z\r\n * @param int \$b\r\n * XYZ\r\n */",
  670. "<?php\r\n/**\r\n * @param int \$z\r\n * @param int \$b\r\n * XYZ\r\n */",
  671. new WhitespacesFixerConfig(' ', "\r\n"),
  672. ],
  673. ];
  674. }
  675. public function testCanFixBadFormatted(): void
  676. {
  677. $this->fixer->configure(['tags' => ['var']]);
  678. $expected = "<?php\n /**\n * @var Foo */\n";
  679. $this->doTest($expected);
  680. }
  681. public function testFixUnicode(): void
  682. {
  683. $this->fixer->configure(['tags' => ['param', 'return']]);
  684. $expected = <<<'EOF'
  685. <?php
  686. /**
  687. * Method test.
  688. *
  689. * @param int $foobar Description
  690. * @param string $foo Description
  691. * @param mixed $bar Description word_with_ą
  692. * @param int|null $test Description
  693. */
  694. $a = 1;
  695. /**
  696. * @return string
  697. * @SuppressWarnings(PHPMD.UnusedLocalVariable) word_with_ą
  698. */
  699. $b = 1;
  700. EOF;
  701. $input = <<<'EOF'
  702. <?php
  703. /**
  704. * Method test.
  705. *
  706. * @param int $foobar Description
  707. * @param string $foo Description
  708. * @param mixed $bar Description word_with_ą
  709. * @param int|null $test Description
  710. */
  711. $a = 1;
  712. /**
  713. * @return string
  714. * @SuppressWarnings(PHPMD.UnusedLocalVariable) word_with_ą
  715. */
  716. $b = 1;
  717. EOF;
  718. $this->doTest($expected, $input);
  719. }
  720. public function testDoesAlignPropertyByDefault(): void
  721. {
  722. $expected = <<<'EOF'
  723. <?php
  724. /**
  725. * @param int $foobar Description
  726. * @return int
  727. * @throws Exception
  728. * @var FooBar
  729. * @type BarFoo
  730. * @property string $foo Hello World
  731. */
  732. EOF;
  733. $input = <<<'EOF'
  734. <?php
  735. /**
  736. * @param int $foobar Description
  737. * @return int
  738. * @throws Exception
  739. * @var FooBar
  740. * @type BarFoo
  741. * @property string $foo Hello World
  742. */
  743. EOF;
  744. $this->doTest($expected, $input);
  745. }
  746. public function testAlignsProperty(): void
  747. {
  748. $this->fixer->configure(['tags' => ['param', 'property', 'return', 'throws', 'type', 'var']]);
  749. $expected = <<<'EOF'
  750. <?php
  751. /**
  752. * @param int $foobar Description
  753. * @return int
  754. * @throws Exception
  755. * @var FooBar
  756. * @type BarFoo
  757. * @property string $foo Hello World
  758. */
  759. EOF;
  760. $input = <<<'EOF'
  761. <?php
  762. /**
  763. * @param int $foobar Description
  764. * @return int
  765. * @throws Exception
  766. * @var FooBar
  767. * @type BarFoo
  768. * @property string $foo Hello World
  769. */
  770. EOF;
  771. $this->doTest($expected, $input);
  772. }
  773. public function testDoesAlignMethodByDefault(): void
  774. {
  775. $expected = <<<'EOF'
  776. <?php
  777. /**
  778. * @param int $foobar Description
  779. * @return int
  780. * @throws Exception
  781. * @var FooBar
  782. * @type BarFoo
  783. * @method string foo(string $bar) Hello World
  784. */
  785. EOF;
  786. $input = <<<'EOF'
  787. <?php
  788. /**
  789. * @param int $foobar Description
  790. * @return int
  791. * @throws Exception
  792. * @var FooBar
  793. * @type BarFoo
  794. * @method string foo(string $bar) Hello World
  795. */
  796. EOF;
  797. $this->doTest($expected, $input);
  798. }
  799. public function testAlignsMethod(): void
  800. {
  801. $this->fixer->configure(['tags' => ['param', 'method', 'return', 'throws', 'type', 'var']]);
  802. $expected = <<<'EOF'
  803. <?php
  804. /**
  805. * @param int $foobar Description
  806. * @return int
  807. * @throws Exception
  808. * @var FooBar
  809. * @type BarFoo
  810. * @method int foo(string $bar, string ...$things, int &$baz) Description
  811. */
  812. EOF;
  813. $input = <<<'EOF'
  814. <?php
  815. /**
  816. * @param int $foobar Description
  817. * @return int
  818. * @throws Exception
  819. * @var FooBar
  820. * @type BarFoo
  821. * @method int foo(string $bar, string ...$things, int &$baz) Description
  822. */
  823. EOF;
  824. $this->doTest($expected, $input);
  825. }
  826. public function testAlignsMethodWithoutParameters(): void
  827. {
  828. $this->fixer->configure(['tags' => ['method', 'property']]);
  829. $expected = <<<'EOF'
  830. <?php
  831. /**
  832. * @property string $foo Desc
  833. * @method int foo() Description
  834. */
  835. EOF;
  836. $input = <<<'EOF'
  837. <?php
  838. /**
  839. * @property string $foo Desc
  840. * @method int foo() Description
  841. */
  842. EOF;
  843. $this->doTest($expected, $input);
  844. }
  845. public function testAlignsMethodWithoutParametersLeftAlign(): void
  846. {
  847. $this->fixer->configure(['tags' => ['method', 'property'], 'align' => PhpdocAlignFixer::ALIGN_LEFT]);
  848. $expected = <<<'EOF'
  849. <?php
  850. /**
  851. * @property string $foo Desc
  852. * @method int foo() Description
  853. */
  854. EOF;
  855. $input = <<<'EOF'
  856. <?php
  857. /**
  858. * @property string $foo Desc
  859. * @method int foo() Description
  860. */
  861. EOF;
  862. $this->doTest($expected, $input);
  863. }
  864. public function testDoesNotFormatMethod(): void
  865. {
  866. $this->fixer->configure(['tags' => ['method']]);
  867. $input = <<<'EOF'
  868. <?php
  869. /**
  870. * @method int foo( string $bar ) Description
  871. */
  872. EOF;
  873. $this->doTest($input);
  874. }
  875. public function testAlignsMethodWithoutReturnType(): void
  876. {
  877. $this->fixer->configure(['tags' => ['method', 'property']]);
  878. $expected = <<<'EOF'
  879. <?php
  880. /**
  881. * @property string $foo Desc
  882. * @method int foo() Description
  883. * @method bar() Descrip
  884. */
  885. EOF;
  886. $input = <<<'EOF'
  887. <?php
  888. /**
  889. * @property string $foo Desc
  890. * @method int foo() Description
  891. * @method bar() Descrip
  892. */
  893. EOF;
  894. $this->doTest($expected, $input);
  895. }
  896. public function testAlignsMethodsWithoutReturnType(): void
  897. {
  898. $this->fixer->configure(['tags' => ['method']]);
  899. $expected = <<<'EOF'
  900. <?php
  901. /**
  902. * @method fooBaz() Description
  903. * @method bar(string $foo) Descrip
  904. */
  905. EOF;
  906. $input = <<<'EOF'
  907. <?php
  908. /**
  909. * @method fooBaz() Description
  910. * @method bar(string $foo) Descrip
  911. */
  912. EOF;
  913. $this->doTest($expected, $input);
  914. }
  915. public function testAlignsStaticAndNonStaticMethods(): void
  916. {
  917. $this->fixer->configure(['tags' => ['method', 'property']]);
  918. $expected = <<<'EOF'
  919. <?php
  920. /**
  921. * @property string $foo Desc1
  922. * @property int $bar Desc2
  923. * @method foo(string $foo) DescriptionFoo
  924. * @method static bar(string $foo) DescriptionBar
  925. * @method string|null baz(bool $baz) DescriptionBaz
  926. * @method static int|false qux(float $qux) DescriptionQux
  927. * @method static static quux(int $quux) DescriptionQuux
  928. * @method static $this quuz(bool $quuz) DescriptionQuuz
  929. */
  930. EOF;
  931. $input = <<<'EOF'
  932. <?php
  933. /**
  934. * @property string $foo Desc1
  935. * @property int $bar Desc2
  936. * @method foo(string $foo) DescriptionFoo
  937. * @method static bar(string $foo) DescriptionBar
  938. * @method string|null baz(bool $baz) DescriptionBaz
  939. * @method static int|false qux(float $qux) DescriptionQux
  940. * @method static static quux(int $quux) DescriptionQuux
  941. * @method static $this quuz(bool $quuz) DescriptionQuuz
  942. */
  943. EOF;
  944. $this->doTest($expected, $input);
  945. }
  946. public function testAlignsStaticAndNonStaticMethodsLeftAlign(): void
  947. {
  948. $this->fixer->configure(['tags' => ['method', 'property'], 'align' => PhpdocAlignFixer::ALIGN_LEFT]);
  949. $expected = <<<'EOF'
  950. <?php
  951. /**
  952. * @property string $foo Desc1
  953. * @property int $bar Desc2
  954. * @method foo(string $foo) DescriptionFoo
  955. * @method static bar(string $foo) DescriptionBar
  956. * @method string|null baz(bool $baz) DescriptionBaz
  957. * @method static int|false qux(float $qux) DescriptionQux
  958. * @method static static quux(int $quux) DescriptionQuux
  959. * @method static $this quuz(bool $quuz) DescriptionQuuz
  960. */
  961. EOF;
  962. $input = <<<'EOF'
  963. <?php
  964. /**
  965. * @property string $foo Desc1
  966. * @property int $bar Desc2
  967. * @method foo(string $foo) DescriptionFoo
  968. * @method static bar(string $foo) DescriptionBar
  969. * @method string|null baz(bool $baz) DescriptionBaz
  970. * @method static int|false qux(float $qux) DescriptionQux
  971. * @method static static quux(int $quux) DescriptionQuux
  972. * @method static $this quuz(bool $quuz) DescriptionQuuz
  973. */
  974. EOF;
  975. $this->doTest($expected, $input);
  976. }
  977. public function testAlignsReturnStatic(): void
  978. {
  979. $this->fixer->configure(['tags' => ['param', 'return', 'throws']]);
  980. $expected = <<<'EOF'
  981. <?php
  982. /**
  983. * @param string $foobar Desc1
  984. * @param int &$baz Desc2
  985. * @param ?Qux $qux Desc3
  986. * @param int|float $quux Desc4
  987. * @return static DescriptionReturn
  988. * @throws Exception DescriptionException
  989. */
  990. EOF;
  991. $input = <<<'EOF'
  992. <?php
  993. /**
  994. * @param string $foobar Desc1
  995. * @param int &$baz Desc2
  996. * @param ?Qux $qux Desc3
  997. * @param int|float $quux Desc4
  998. * @return static DescriptionReturn
  999. * @throws Exception DescriptionException
  1000. */
  1001. EOF;
  1002. $this->doTest($expected, $input);
  1003. }
  1004. public function testAlignsReturnStaticLeftAlign(): void
  1005. {
  1006. $this->fixer->configure(['tags' => ['param', 'return', 'throws'], 'align' => PhpdocAlignFixer::ALIGN_LEFT]);
  1007. $expected = <<<'EOF'
  1008. <?php
  1009. /**
  1010. * @param string $foobar Desc1
  1011. * @param int &$baz Desc2
  1012. * @param ?Qux $qux Desc3
  1013. * @param int|float $quux Desc4
  1014. * @return static DescriptionReturn
  1015. * @throws Exception DescriptionException
  1016. */
  1017. EOF;
  1018. $input = <<<'EOF'
  1019. <?php
  1020. /**
  1021. * @param string $foobar Desc1
  1022. * @param int &$baz Desc2
  1023. * @param ?Qux $qux Desc3
  1024. * @param int|float $quux Desc4
  1025. * @return static DescriptionReturn
  1026. * @throws Exception DescriptionException
  1027. */
  1028. EOF;
  1029. $this->doTest($expected, $input);
  1030. }
  1031. public function testDoesNotAlignWithEmptyConfig(): void
  1032. {
  1033. $this->fixer->configure(['tags' => []]);
  1034. $input = <<<'EOF'
  1035. <?php
  1036. /**
  1037. * @param int $foobar Description
  1038. * @return int
  1039. * @throws Exception
  1040. * @var FooBar
  1041. * @type BarFoo
  1042. * @property string $foo Hello World
  1043. * @method int bar() Description
  1044. */
  1045. EOF;
  1046. $this->doTest($input);
  1047. }
  1048. /**
  1049. * @param array<string, mixed> $config
  1050. *
  1051. * @dataProvider provideVariadicCases
  1052. */
  1053. public function testVariadicParams(array $config, string $expected, string $input): void
  1054. {
  1055. $this->fixer->configure($config);
  1056. $this->doTest($expected, $input);
  1057. }
  1058. public static function provideVariadicCases(): array
  1059. {
  1060. return [
  1061. [
  1062. ['tags' => ['param']],
  1063. '<?php
  1064. final class Sample
  1065. {
  1066. /**
  1067. * @param int[] $a A
  1068. * @param int &$b B
  1069. * @param array ...$c C
  1070. */
  1071. public function sample2($a, &$b, ...$c)
  1072. {
  1073. }
  1074. }
  1075. ',
  1076. '<?php
  1077. final class Sample
  1078. {
  1079. /**
  1080. * @param int[] $a A
  1081. * @param int &$b B
  1082. * @param array ...$c C
  1083. */
  1084. public function sample2($a, &$b, ...$c)
  1085. {
  1086. }
  1087. }
  1088. ',
  1089. ],
  1090. [
  1091. ['tags' => ['param']],
  1092. '<?php
  1093. final class Sample
  1094. {
  1095. /**
  1096. * @param int $a
  1097. * @param int $b
  1098. * @param array[] ...$c
  1099. */
  1100. public function sample2($a, $b, ...$c)
  1101. {
  1102. }
  1103. }
  1104. ',
  1105. '<?php
  1106. final class Sample
  1107. {
  1108. /**
  1109. * @param int $a
  1110. * @param int $b
  1111. * @param array[] ...$c
  1112. */
  1113. public function sample2($a, $b, ...$c)
  1114. {
  1115. }
  1116. }
  1117. ',
  1118. ],
  1119. [
  1120. ['tags' => ['param'], 'align' => PhpdocAlignFixer::ALIGN_LEFT],
  1121. '<?php
  1122. final class Sample
  1123. {
  1124. /**
  1125. * @param int $a
  1126. * @param int $b
  1127. * @param array[] ...$c
  1128. */
  1129. public function sample2($a, $b, ...$c)
  1130. {
  1131. }
  1132. }
  1133. ',
  1134. '<?php
  1135. final class Sample
  1136. {
  1137. /**
  1138. * @param int $a
  1139. * @param int $b
  1140. * @param array[] ...$c
  1141. */
  1142. public function sample2($a, $b, ...$c)
  1143. {
  1144. }
  1145. }
  1146. ',
  1147. ],
  1148. [
  1149. ['tags' => ['property', 'property-read', 'property-write']],
  1150. '<?php
  1151. /**
  1152. * @property string $myMagicProperty magic property
  1153. * @property-read string $myMagicReadProperty magic read-only property
  1154. * @property-write string $myMagicWriteProperty magic write-only property
  1155. */
  1156. class Foo {}
  1157. ',
  1158. '<?php
  1159. /**
  1160. * @property string $myMagicProperty magic property
  1161. * @property-read string $myMagicReadProperty magic read-only property
  1162. * @property-write string $myMagicWriteProperty magic write-only property
  1163. */
  1164. class Foo {}
  1165. ',
  1166. ],
  1167. ];
  1168. }
  1169. /**
  1170. * @param array<string, mixed> $config
  1171. *
  1172. * @dataProvider provideInvalidPhpdocCases
  1173. */
  1174. public function testInvalidPhpdocsAreUnchanged(array $config, string $input): void
  1175. {
  1176. $this->fixer->configure($config);
  1177. $this->doTest($input);
  1178. }
  1179. public static function provideInvalidPhpdocCases(): array
  1180. {
  1181. return [
  1182. [
  1183. ['tags' => ['param', 'return', 'throws', 'type', 'var']],
  1184. '<?php
  1185. /**
  1186. * @ Security("is_granted(\'CANCEL\', giftCard)")
  1187. */
  1188. ',
  1189. ],
  1190. [
  1191. ['tags' => ['param', 'return', 'throws', 'type', 'var', 'method']],
  1192. '<?php
  1193. /**
  1194. * @ Security("is_granted(\'CANCEL\', giftCard)")
  1195. */
  1196. ',
  1197. ],
  1198. [
  1199. ['tags' => ['param', 'return', 'throws', 'type', 'var']],
  1200. '<?php
  1201. /**
  1202. * @ Security("is_granted(\'CANCEL\', giftCard)")
  1203. * @ foo bar
  1204. * @ foo
  1205. */
  1206. ',
  1207. ],
  1208. ];
  1209. }
  1210. public function testTypesContainingCallables(): void
  1211. {
  1212. $this->doTest(
  1213. '<?php
  1214. /**
  1215. * @param callable(Foo): Bar $x Description
  1216. * @param callable(FooFoo): BarBar $yy Description
  1217. */
  1218. ',
  1219. '<?php
  1220. /**
  1221. * @param callable(Foo): Bar $x Description
  1222. * @param callable(FooFoo): BarBar $yy Description
  1223. */
  1224. '
  1225. );
  1226. }
  1227. public function testTypesContainingWhitespace(): void
  1228. {
  1229. $this->doTest('<?php
  1230. /**
  1231. * @var int $key
  1232. * @var iterable<int, string> $value
  1233. */
  1234. /**
  1235. * @param array<int, $this> $arrayOfIntegers
  1236. * @param array<string, $this> $arrayOfStrings
  1237. */
  1238. ');
  1239. }
  1240. public function testClosureTypesContainingBackslash(): void
  1241. {
  1242. $this->doTest('<?php
  1243. /**
  1244. * @var string $input
  1245. * @var \Closure $fn
  1246. * @var \Closure(bool):int $fn2
  1247. * @var Closure $fn3
  1248. * @var Closure(string):string $fn4
  1249. * @var array<string,array<string,mixed>> $data
  1250. */
  1251. /**
  1252. * @param string $input
  1253. * @param \Closure $fn
  1254. * @param \Closure(bool):int $fn2
  1255. * @param Closure $fn3
  1256. * @param Closure(string):string $fn4
  1257. * @param array<string,array<string,mixed>> $data
  1258. */
  1259. /**
  1260. * @var string $value
  1261. * @var \Closure(string): string $callback
  1262. * @var Closure(int): bool $callback2
  1263. */
  1264. /**
  1265. * @param string $value
  1266. * @param \Closure(string): string $callback
  1267. * @param Closure(int): bool $callback2
  1268. */
  1269. /**
  1270. * @var Closure(array<int,bool>): bool $callback1
  1271. * @var \Closure(string): string $callback2
  1272. */
  1273. /**
  1274. * @param Closure(array<int,bool>): bool $callback1
  1275. * @param \Closure(string): string $callback2
  1276. */
  1277. ');
  1278. }
  1279. /**
  1280. * @dataProvider provideCallableTypesWithUglyCodeCases
  1281. */
  1282. public function testCallableTypesWithUglyCode(string $input): void
  1283. {
  1284. $this->doTest(<<<'EOT'
  1285. <?php
  1286. /**
  1287. * @var callable $fn
  1288. * @var callable(bool): int $fn2
  1289. * @var Closure $fn3
  1290. * @var Closure(string|object):string $fn4
  1291. * @var \Closure $fn5
  1292. * @var \Closure(int, bool): bool $fn6
  1293. */
  1294. EOT, $input);
  1295. }
  1296. public static function provideCallableTypesWithUglyCodeCases(): iterable
  1297. {
  1298. yield [<<<'EOT'
  1299. <?php
  1300. /**
  1301. * @var callable $fn
  1302. * @var callable(bool): int $fn2
  1303. * @var Closure $fn3
  1304. * @var Closure(string|object):string $fn4
  1305. * @var \Closure $fn5
  1306. * @var \Closure(int, bool): bool $fn6
  1307. */
  1308. EOT];
  1309. yield [<<<'EOT'
  1310. <?php
  1311. /**
  1312. * @var callable $fn
  1313. * @var callable(bool): int $fn2
  1314. * @var Closure $fn3
  1315. * @var Closure(string|object):string $fn4
  1316. * @var \Closure $fn5
  1317. * @var \Closure(int, bool): bool $fn6
  1318. */
  1319. EOT];
  1320. }
  1321. }