OrderedTypesFixerTest.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  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\Tests\Test\AbstractFixerTestCase;
  14. /**
  15. * @author John Paul E. Balandan, CPA <paulbalandan@gmail.com>
  16. *
  17. * @internal
  18. *
  19. * @covers \PhpCsFixer\Fixer\ClassNotation\OrderedTypesFixer
  20. */
  21. final class OrderedTypesFixerTest extends AbstractFixerTestCase
  22. {
  23. /**
  24. * @dataProvider provideFixCases
  25. *
  26. * @param null|array<string, string> $config
  27. */
  28. public function testFix(string $expected, ?string $input = null, ?array $config = null): void
  29. {
  30. if (null !== $config) {
  31. $this->fixer->configure($config);
  32. }
  33. $this->doTest($expected, $input);
  34. }
  35. /**
  36. * @return iterable<string, (null|array<string, string>|string)[]|string[]>
  37. */
  38. public static function provideFixCases(): iterable
  39. {
  40. yield 'catch with default, no spaces, with both leading slash' => [
  41. '<?php
  42. try {
  43. $this->foo();
  44. } catch (\LogicException|\RuntimeException $e) {
  45. // $e
  46. }
  47. ',
  48. '<?php
  49. try {
  50. $this->foo();
  51. } catch (\RuntimeException|\LogicException $e) {
  52. // $e
  53. }
  54. ',
  55. ];
  56. yield 'catch with default, with spaces, with both leading slash' => [
  57. '<?php
  58. try {
  59. $this->foo();
  60. } catch (\LogicException|\RuntimeException $e) {
  61. // $e
  62. }
  63. ',
  64. '<?php
  65. try {
  66. $this->foo();
  67. } catch (\RuntimeException | \LogicException $e) {
  68. // $e
  69. }
  70. ',
  71. ];
  72. yield 'catch with default, no spaces, with no leading slash' => [
  73. '<?php
  74. try {
  75. cache()->save();
  76. } catch (CacheException|SimpleCacheException $e) {
  77. // $e
  78. }
  79. ',
  80. '<?php
  81. try {
  82. cache()->save();
  83. } catch (SimpleCacheException|CacheException $e) {
  84. // $e
  85. }
  86. ',
  87. ];
  88. yield 'catch with default, with spaces, with one leading slash' => [
  89. '<?php
  90. try {
  91. cache()->save();
  92. } catch (CacheException|\RuntimeException $e) {
  93. // $e
  94. }
  95. ',
  96. '<?php
  97. try {
  98. cache()->save();
  99. } catch (\RuntimeException | CacheException $e) {
  100. // $e
  101. }
  102. ',
  103. ];
  104. yield 'catch with no sorting' => [
  105. '<?php
  106. try {
  107. $this->foo();
  108. } catch (\RuntimeException|\LogicException $e) {
  109. // $e
  110. }
  111. ',
  112. null,
  113. ['sort_algorithm' => 'none'],
  114. ];
  115. yield 'nothing to fix' => [
  116. '<?php
  117. try {
  118. $this->foo();
  119. } catch (\LogicException $e) {
  120. // $e
  121. }
  122. ',
  123. ];
  124. yield 'already fixed' => [
  125. '<?php
  126. try {
  127. $this->foo();
  128. } catch (LogicException|RuntimeException $e) {
  129. // $e
  130. }
  131. ',
  132. ];
  133. }
  134. /**
  135. * @dataProvider provideFixPhp80Cases
  136. *
  137. * @param null|array<string, string> $config
  138. *
  139. * @requires PHP 8.0
  140. */
  141. public function testFixPhp80(string $expected, ?string $input = null, ?array $config = null): void
  142. {
  143. if (null !== $config) {
  144. $this->fixer->configure($config);
  145. }
  146. $this->doTest($expected, $input);
  147. }
  148. /**
  149. * @return iterable<(null|array<string, string>|string)[]>
  150. */
  151. public static function provideFixPhp80Cases(): iterable
  152. {
  153. yield 'sort alpha, null none' => [
  154. "<?php\nclass Foo\n{\n public A|null|Z \$bar;\n}\n",
  155. "<?php\nclass Foo\n{\n public Z|null|A \$bar;\n}\n",
  156. ['sort_algorithm' => 'alpha', 'null_adjustment' => 'none'],
  157. ];
  158. yield 'sort alpha, null first' => [
  159. "<?php\nclass Foo\n{\n public null|A|Z \$bar;\n}\n",
  160. "<?php\nclass Foo\n{\n public Z|null|A \$bar;\n}\n",
  161. ['sort_algorithm' => 'alpha', 'null_adjustment' => 'always_first'],
  162. ];
  163. yield 'sort alpha, null last' => [
  164. "<?php\nclass Foo\n{\n public A|Z|null \$bar;\n}\n",
  165. "<?php\nclass Foo\n{\n public Z|null|A \$bar;\n}\n",
  166. ['sort_algorithm' => 'alpha', 'null_adjustment' => 'always_last'],
  167. ];
  168. yield 'sort none, null first' => [
  169. "<?php\nclass Foo\n{\n public null|Z|A \$bar;\n}\n",
  170. "<?php\nclass Foo\n{\n public Z|null|A \$bar;\n}\n",
  171. ['sort_algorithm' => 'none', 'null_adjustment' => 'always_first'],
  172. ];
  173. yield 'sort none, null last' => [
  174. "<?php\nclass Foo\n{\n public Z|A|null \$bar;\n}\n",
  175. "<?php\nclass Foo\n{\n public Z|null|A \$bar;\n}\n",
  176. ['sort_algorithm' => 'none', 'null_adjustment' => 'always_last'],
  177. ];
  178. yield 'sort none, null none' => [
  179. "<?php\nclass Foo\n{\n public Z|null|A \$bar;\n}\n",
  180. null,
  181. ['sort_algorithm' => 'none', 'null_adjustment' => 'none'],
  182. ];
  183. }
  184. /**
  185. * @dataProvider provideFixDefaultCases
  186. *
  187. * @requires PHP 8.0
  188. */
  189. public function testFixDefault(string $expected, ?string $input = null): void
  190. {
  191. $this->doTest($expected, $input);
  192. }
  193. /**
  194. * @return iterable<(null|array<string, string>|string)[]|string[]>
  195. */
  196. public static function provideFixDefaultCases(): iterable
  197. {
  198. yield [
  199. "<?php\nclass Foo\n{\n public null|int|string \$bar = null;\n}\n",
  200. "<?php\nclass Foo\n{\n public string|null|int \$bar = null;\n}\n",
  201. ];
  202. yield [
  203. "<?php\nclass Foo\n{\n public null|A|B \$foo = null;\n}\n",
  204. "<?php\nclass Foo\n{\n public B|A|null \$foo = null;\n}\n",
  205. ];
  206. yield [
  207. "<?php\nclass Foo\n{\n public null|\\A|B \$foo = null;\n}\n",
  208. "<?php\nclass Foo\n{\n public B|\\A|null \$foo = null;\n}\n",
  209. ];
  210. yield [
  211. "<?php\nclass Foo\n{\n public null|\\A|\\B \$foo = null;\n}\n",
  212. "<?php\nclass Foo\n{\n public \\B|\\A|null \$foo = null;\n}\n",
  213. ];
  214. yield [
  215. "<?php\nclass Foo\n{\n public null|int|string/* array */ \$bar = null;\n}\n",
  216. "<?php\nclass Foo\n{\n public string|null|int/* array */ \$bar = null;\n}\n",
  217. ];
  218. yield [
  219. "<?php\nclass Foo\n{\n public /* int */null|A|B \$foo = null;\n}\n",
  220. "<?php\nclass Foo\n{\n public /* int */B|A|null \$foo = null;\n}\n",
  221. ];
  222. yield [
  223. "<?php\nclass Foo\n{\n public null|A|B \$foo = null;\n}\n",
  224. "<?php\nclass Foo\n{\n public B|A|null \$foo = null;\n}\n",
  225. ];
  226. yield [
  227. "<?php\nclass Foo\n{\n private function bar(null|array|callable|int \$cb) {}\n}\n",
  228. "<?php\nclass Foo\n{\n private function bar(array|int|callable|null \$cb) {}\n}\n",
  229. ];
  230. yield [
  231. "<?php\nclass Foo\n{\n private function bar(\$cb): null|array|callable|int {}\n}\n",
  232. "<?php\nclass Foo\n{\n private function bar(\$cb): array|int|callable|null {}\n}\n",
  233. ];
  234. yield [
  235. "<?php\nclass Foo\n{\n private function bar(\$cb): null|static {}\n}\n",
  236. "<?php\nclass Foo\n{\n private function bar(\$cb): static|null {}\n}\n",
  237. ];
  238. yield [
  239. "<?php\nclass Foo\n{\n public function bar(null|string \$str, null|array|int \$arr) {}\n}\n",
  240. "<?php\nclass Foo\n{\n public function bar(string|null \$str, int|array|null \$arr) {}\n}\n",
  241. ];
  242. yield [
  243. "<?php\nclass Foo\n{\n public function bar(\\JsonSerializable|\\Stringable \$obj): array|int {}\n}\n",
  244. "<?php\nclass Foo\n{\n public function bar(\\Stringable|\\JsonSerializable \$obj): int|array {}\n}\n",
  245. ];
  246. yield [
  247. '<?php function foo(null|int|string $bar): null|\Stringable {}',
  248. '<?php function foo(string|int|null $bar): \Stringable|null {}',
  249. ];
  250. yield [
  251. '<?php fn (null|\Countable|int $number): null|int => $number;',
  252. '<?php fn (int|\Countable|null $number): int|null => $number;',
  253. ];
  254. yield [
  255. "<?php\ntry {\n foo();\n} catch (\\Error|\\TypeError) {\n}\n",
  256. "<?php\ntry {\n foo();\n} catch (\\TypeError|\\Error) {\n}\n",
  257. ];
  258. yield [
  259. '<?php
  260. class Foo
  261. {
  262. public ?string $foo = null;
  263. public /* int|string */ $bar;
  264. private null|array $baz = null;
  265. public function baz(): null|string {}
  266. protected function bar(string $str, ?array $config = null): callable {}
  267. }
  268. try {
  269. (new Foo)->baz();
  270. } catch (Exception $e) {
  271. return $e;
  272. }
  273. ',
  274. ];
  275. }
  276. /**
  277. * @dataProvider provideFixWithAlphaAlgorithmAndNullAlwaysLastCases
  278. *
  279. * @requires PHP 8.0
  280. */
  281. public function testFixWithAlphaAlgorithmAndNullAlwaysLast(string $expected, ?string $input = null): void
  282. {
  283. $this->fixer->configure([
  284. 'sort_algorithm' => 'alpha',
  285. 'null_adjustment' => 'always_last',
  286. ]);
  287. $this->doTest($expected, $input);
  288. }
  289. /**
  290. * @return iterable<(null|string|string[])[]|string[]>
  291. */
  292. public static function provideFixWithAlphaAlgorithmAndNullAlwaysLastCases(): iterable
  293. {
  294. yield [
  295. "<?php\nclass Foo\n{\n public int|string|null \$bar = null;\n}\n",
  296. "<?php\nclass Foo\n{\n public string|null|int \$bar = null;\n}\n",
  297. ];
  298. yield [
  299. "<?php\nclass Foo\n{\n public A|B|null \$foo = null;\n}\n",
  300. "<?php\nclass Foo\n{\n public B|A|null \$foo = null;\n}\n",
  301. ];
  302. yield [
  303. "<?php\nclass Foo\n{\n public \\A|B|null \$foo = null;\n}\n",
  304. "<?php\nclass Foo\n{\n public B|\\A|null \$foo = null;\n}\n",
  305. ];
  306. yield [
  307. "<?php\nclass Foo\n{\n public \\A|\\B|null \$foo = null;\n}\n",
  308. "<?php\nclass Foo\n{\n public \\B|\\A|null \$foo = null;\n}\n",
  309. ];
  310. yield [
  311. "<?php\nclass Foo\n{\n public int|string|null/* array */ \$bar = null;\n}\n",
  312. "<?php\nclass Foo\n{\n public string|null|int/* array */ \$bar = null;\n}\n",
  313. ];
  314. yield [
  315. "<?php\nclass Foo\n{\n public /* int */A|B|null \$foo = null;\n}\n",
  316. "<?php\nclass Foo\n{\n public /* int */B|A|null \$foo = null;\n}\n",
  317. ];
  318. yield [
  319. "<?php\nclass Foo\n{\n public A|B|null \$foo = null;\n}\n",
  320. "<?php\nclass Foo\n{\n public B|A|null \$foo = null;\n}\n",
  321. ];
  322. yield [
  323. "<?php\nclass Foo\n{\n private function bar(array|callable|int|null \$cb) {}\n}\n",
  324. "<?php\nclass Foo\n{\n private function bar(array|int|callable|null \$cb) {}\n}\n",
  325. ];
  326. yield [
  327. "<?php\nclass Foo\n{\n private function bar(\$cb): array|callable|int|null {}\n}\n",
  328. "<?php\nclass Foo\n{\n private function bar(\$cb): array|int|callable|null {}\n}\n",
  329. ];
  330. yield [
  331. "<?php\nclass Foo\n{\n private function bar(\$cb): static|null {}\n}\n",
  332. "<?php\nclass Foo\n{\n private function bar(\$cb): null|static {}\n}\n",
  333. ];
  334. yield [
  335. "<?php\nclass Foo\n{\n public function bar(string|null \$str, array|int|null \$arr) {}\n}\n",
  336. "<?php\nclass Foo\n{\n public function bar(string|null \$str, int|array|null \$arr) {}\n}\n",
  337. ];
  338. yield [
  339. "<?php\nclass Foo\n{\n public function bar(\\JsonSerializable|\\Stringable \$obj): array|int {}\n}\n",
  340. "<?php\nclass Foo\n{\n public function bar(\\Stringable|\\JsonSerializable \$obj): int|array {}\n}\n",
  341. ];
  342. yield [
  343. '<?php function foo(int|string|null $bar): \Stringable|null {}',
  344. '<?php function foo(string|int|null $bar): \Stringable|null {}',
  345. ];
  346. yield [
  347. '<?php fn (\Countable|int|null $number): int|null => $number;',
  348. '<?php fn (int|\Countable|null $number): int|null => $number;',
  349. ];
  350. yield [
  351. "<?php\ntry {\n foo();\n} catch (\\Error|\\TypeError) {\n}\n",
  352. "<?php\ntry {\n foo();\n} catch (\\TypeError|\\Error) {\n}\n",
  353. ];
  354. yield [
  355. '<?php
  356. class Foo
  357. {
  358. public ?string $foo = null;
  359. public /* int|string */ $bar;
  360. private array|null $baz = null;
  361. public function baz(): string|null {}
  362. protected function bar(string $str, ?array $config = null): callable {}
  363. }
  364. try {
  365. (new Foo)->baz();
  366. } catch (Exception $e) {
  367. return $e;
  368. }
  369. ',
  370. ];
  371. }
  372. /**
  373. * @dataProvider provideFixWithAlphaAlgorithmOnlyCases
  374. *
  375. * @requires PHP 8.0
  376. */
  377. public function testFixWithAlphaAlgorithmOnly(string $expected, ?string $input = null): void
  378. {
  379. $this->fixer->configure([
  380. 'sort_algorithm' => 'alpha',
  381. 'null_adjustment' => 'none',
  382. ]);
  383. $this->doTest($expected, $input);
  384. }
  385. /**
  386. * @return iterable<(null|array<string, string>|string)[]|string[]>
  387. */
  388. public static function provideFixWithAlphaAlgorithmOnlyCases(): iterable
  389. {
  390. yield [
  391. "<?php\nclass Foo\n{\n public int|null|string \$bar = null;\n}\n",
  392. "<?php\nclass Foo\n{\n public string|null|int \$bar = null;\n}\n",
  393. ];
  394. yield [
  395. "<?php\nclass Foo\n{\n public A|B|null \$foo = null;\n}\n",
  396. "<?php\nclass Foo\n{\n public B|A|null \$foo = null;\n}\n",
  397. ];
  398. yield [
  399. "<?php\nclass Foo\n{\n public \\A|B|null \$foo = null;\n}\n",
  400. "<?php\nclass Foo\n{\n public B|\\A|null \$foo = null;\n}\n",
  401. ];
  402. yield [
  403. "<?php\nclass Foo\n{\n public \\A|\\B|null \$foo = null;\n}\n",
  404. "<?php\nclass Foo\n{\n public \\B|\\A|null \$foo = null;\n}\n",
  405. ];
  406. yield [
  407. "<?php\nclass Foo\n{\n public int|null|string/* array */ \$bar = null;\n}\n",
  408. "<?php\nclass Foo\n{\n public string|null|int/* array */ \$bar = null;\n}\n",
  409. ];
  410. yield [
  411. "<?php\nclass Foo\n{\n public /* int */A|B|null \$foo = null;\n}\n",
  412. "<?php\nclass Foo\n{\n public /* int */B|A|null \$foo = null;\n}\n",
  413. ];
  414. yield [
  415. "<?php\nclass Foo\n{\n public A|B|null \$foo = null;\n}\n",
  416. "<?php\nclass Foo\n{\n public B|A|null \$foo = null;\n}\n",
  417. ];
  418. yield [
  419. "<?php\nclass Foo\n{\n private function bar(array|callable|int|null \$cb) {}\n}\n",
  420. "<?php\nclass Foo\n{\n private function bar(array|int|callable|null \$cb) {}\n}\n",
  421. ];
  422. yield [
  423. "<?php\nclass Foo\n{\n private function bar(\$cb): array|callable|int|null {}\n}\n",
  424. "<?php\nclass Foo\n{\n private function bar(\$cb): array|int|callable|null {}\n}\n",
  425. ];
  426. yield [
  427. "<?php\nclass Foo\n{\n private function bar(\$cb): null|static {}\n}\n",
  428. "<?php\nclass Foo\n{\n private function bar(\$cb): static|null {}\n}\n",
  429. ];
  430. yield [
  431. "<?php\nclass Foo\n{\n public function bar(null|string \$str, array|int|null \$arr) {}\n}\n",
  432. "<?php\nclass Foo\n{\n public function bar(string|null \$str, int|array|null \$arr) {}\n}\n",
  433. ];
  434. yield [
  435. "<?php\nclass Foo\n{\n public function bar(\\JsonSerializable|\\Stringable \$obj): array|int {}\n}\n",
  436. "<?php\nclass Foo\n{\n public function bar(\\Stringable|\\JsonSerializable \$obj): int|array {}\n}\n",
  437. ];
  438. yield [
  439. '<?php function foo(int|null|string $bar): null|\Stringable {}',
  440. '<?php function foo(string|int|null $bar): \Stringable|null {}',
  441. ];
  442. yield [
  443. '<?php fn (\Countable|int|null $number): int|null => $number;',
  444. '<?php fn (int|\Countable|null $number): int|null => $number;',
  445. ];
  446. yield [
  447. "<?php\ntry {\n foo();\n} catch (\\Error|\\TypeError) {\n}\n",
  448. "<?php\ntry {\n foo();\n} catch (\\TypeError|\\Error) {\n}\n",
  449. ];
  450. yield [
  451. '<?php
  452. class Foo
  453. {
  454. public ?string $foo = null;
  455. public /* int|string */ $bar;
  456. private array|null $baz = null;
  457. public function baz(): null|string {}
  458. protected function bar(string $str, ?array $config = null): callable {}
  459. }
  460. try {
  461. (new Foo)->baz();
  462. } catch (Exception $e) {
  463. return $e;
  464. }
  465. ',
  466. ];
  467. }
  468. /**
  469. * @dataProvider provideFixWithSandwichedWhitespaceOrCommentInTypeCases
  470. *
  471. * @requires PHP 8.0
  472. */
  473. public function testFixWithSandwichedWhitespaceOrCommentInType(string $expected, ?string $input = null): void
  474. {
  475. // The current design of the fixer uses the `TypeAnalysis` class which collects the
  476. // types and ignores whitespaces and comments. These ignored tokens are not accounted
  477. // during instantiation of the TypeAnalysis class, thus we have no way of recovering
  478. // those token information. This test case mainly proves this fact.
  479. $this->doTest($expected, $input);
  480. }
  481. /**
  482. * @return iterable<(null|array<string, string>|string)[]|string[]>
  483. */
  484. public static function provideFixWithSandwichedWhitespaceOrCommentInTypeCases(): iterable
  485. {
  486. yield [
  487. "<?php\nclass Foo\n{\n public null|int|string \$bar = null;\n}\n",
  488. "<?php\nclass Foo\n{\n public string | null | int \$bar = null;\n}\n",
  489. ];
  490. yield [
  491. "<?php\nclass Foo\n{\n public null|int|string \$bar = null;\n}\n",
  492. "<?php\nclass Foo\n{\n public string | null | int \$bar = null;\n}\n",
  493. ];
  494. yield [
  495. "<?php\nclass Foo\n{\n public null|int|string \$bar = null;\n}\n",
  496. "<?php\nclass Foo\n{\n public string |/* array| */null|int \$bar = null;\n}\n",
  497. ];
  498. yield [
  499. "<?php\nclass Foo\n{\n private function bar(\$cb): null|static {}\n}\n",
  500. "<?php\nclass Foo\n{\n private function bar(\$cb): static /* |int */ | null {}\n}\n",
  501. ];
  502. }
  503. /**
  504. * @dataProvider provideFixPhp81Cases
  505. *
  506. * @param null|array<string, string> $config
  507. *
  508. * @requires PHP 8.1
  509. */
  510. public function testFixPhp81(string $expected, ?string $input = null, ?array $config = null): void
  511. {
  512. if (null !== $config) {
  513. $this->fixer->configure($config);
  514. }
  515. $this->doTest($expected, $input);
  516. }
  517. /**
  518. * @return iterable<(null|array<string, string>|string)[]|string[]>
  519. */
  520. public static function provideFixPhp81Cases(): iterable
  521. {
  522. yield [
  523. "<?php\nclass Foo\n{\n public A&B \$bar;\n}\n",
  524. "<?php\nclass Foo\n{\n public B&A \$bar;\n}\n",
  525. ];
  526. yield [
  527. "<?php\nclass Foo\n{\n public Ae&At \$bar;\n}\n",
  528. "<?php\nclass Foo\n{\n public At&Ae \$bar;\n}\n",
  529. ];
  530. yield [
  531. "<?php\nclass Foo\n{\n public readonly null|A|B \$bar;\n}\n",
  532. "<?php\nclass Foo\n{\n public readonly B|null|A \$bar;\n}\n",
  533. ];
  534. yield [
  535. "<?php\nclass Foo\n{\n public readonly A|B|null \$bar;\n}\n",
  536. "<?php\nclass Foo\n{\n public readonly B|null|A \$bar;\n}\n",
  537. ['null_adjustment' => 'always_last'],
  538. ];
  539. yield [
  540. "<?php\nclass Foo\n{\n public readonly A|null|X \$bar;\n}\n",
  541. "<?php\nclass Foo\n{\n public readonly X|A|null \$bar;\n}\n",
  542. ['null_adjustment' => 'none'],
  543. ];
  544. yield [
  545. "<?php\nclass Foo\n{\n public B&A \$bar;\n}\n",
  546. null,
  547. ['sort_algorithm' => 'none'],
  548. ];
  549. }
  550. /**
  551. * Provisional support for PHP 8.2's Disjunctive Normal Form (DNF) Types.
  552. *
  553. * @dataProvider provideFixPhp82Cases
  554. *
  555. * @param null|array<string, string> $config
  556. *
  557. * @requires PHP 8.2
  558. */
  559. public function testFixPhp82(string $expected, ?string $input = null, ?array $config = null): void
  560. {
  561. if (null !== $config) {
  562. $this->fixer->configure($config);
  563. }
  564. $this->doTest($expected, $input);
  565. }
  566. /**
  567. * @return iterable<(null|array<string, string>|string)[]|string[]>
  568. */
  569. public static function provideFixPhp82Cases(): iterable
  570. {
  571. yield [
  572. "<?php\nclass Foo\n{\n public null|array|(At&Bz)|string \$bar = null;\n}\n",
  573. "<?php\nclass Foo\n{\n public string|(Bz&At)|array|null \$bar = null;\n}\n",
  574. ];
  575. yield [
  576. "<?php\nclass Foo\n{\n public array|(At&Bz)|string|null \$bar = null;\n}\n",
  577. "<?php\nclass Foo\n{\n public string|(Bz&At)|array|null \$bar = null;\n}\n",
  578. ['null_adjustment' => 'always_last'],
  579. ];
  580. yield [
  581. "<?php\nclass Foo\n{\n public array|(At&Bz)|null|string \$bar = null;\n}\n",
  582. "<?php\nclass Foo\n{\n public string|(Bz&At)|array|null \$bar = null;\n}\n",
  583. ['null_adjustment' => 'none'],
  584. ];
  585. yield [
  586. "<?php\nclass Foo\n{\n public (A&B)|(A&C)|(B&D)|(C&D) \$bar;\n}\n",
  587. "<?php\nclass Foo\n{\n public (D&B)|(C&A)|(B&A)|(D&C) \$bar;\n}\n",
  588. ['sort_algorithm' => 'alpha'],
  589. ];
  590. yield [
  591. "<?php\nclass Foo\n{\n public (A&B)|(\\A&C)|(B&\\D)|(C&D) \$bar;\n}\n",
  592. "<?php\nclass Foo\n{\n public (\\D&B)|(C&\\A)|(B&A)|(D&C) \$bar;\n}\n",
  593. ['sort_algorithm' => 'alpha'],
  594. ];
  595. yield [
  596. "<?php\nclass Foo\n{\n public (A&C)|(B&D) \$bar;\n}\n",
  597. "<?php\nclass Foo\n{\n public (D&B)|(C&A) \$bar;\n}\n",
  598. ['sort_algorithm' => 'alpha'],
  599. ];
  600. yield [
  601. "<?php\nclass Foo\n{\n public (\\A&\\C)|(\\B&\\D) \$bar;\n}\n",
  602. "<?php\nclass Foo\n{\n public (\\D&\\B)|(\\C&\\A) \$bar;\n}\n",
  603. ['sort_algorithm' => 'alpha'],
  604. ];
  605. }
  606. /**
  607. * @dataProvider provideFixWithCaseSensitiveCases
  608. *
  609. * @requires PHP 8.0
  610. */
  611. public function testFixWithCaseSensitive(string $expected, ?string $input = null): void
  612. {
  613. $this->fixer->configure([
  614. 'case_sensitive' => true,
  615. ]);
  616. $this->doTest($expected, $input);
  617. }
  618. /**
  619. * @return iterable<(null|array<string, string>|string)[]|string[]>
  620. */
  621. public static function provideFixWithCaseSensitiveCases(): iterable
  622. {
  623. yield [
  624. "<?php\nclass Foo\n{\n public null|AAa|Aa \$bar = null;\n}\n",
  625. "<?php\nclass Foo\n{\n public Aa|AAa|null \$bar = null;\n}\n",
  626. ];
  627. }
  628. }