NoUnneededControlParenthesesFixerTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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\ControlStructure;
  13. use PhpCsFixer\Fixer\ControlStructure\NoUnneededControlParenthesesFixer;
  14. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  15. /**
  16. * @author Sullivan Senechal <soullivaneuh@gmail.com>
  17. * @author Gregor Harlan <gharlan@web.de>
  18. *
  19. * @internal
  20. *
  21. * @covers \PhpCsFixer\Fixer\ControlStructure\NoUnneededControlParenthesesFixer
  22. */
  23. final class NoUnneededControlParenthesesFixerTest extends AbstractFixerTestCase
  24. {
  25. private static $defaultStatements;
  26. public static function setUpBeforeClass(): void
  27. {
  28. parent::setUpBeforeClass();
  29. $fixer = new NoUnneededControlParenthesesFixer();
  30. foreach ($fixer->getConfigurationDefinition()->getOptions() as $option) {
  31. if ('statements' === $option->getName()) {
  32. self::$defaultStatements = $option->getDefault();
  33. break;
  34. }
  35. }
  36. }
  37. /**
  38. * @dataProvider provideFixCases
  39. */
  40. public function testFix(string $expected, ?string $input = null, ?string $fixStatement = null): void
  41. {
  42. $this->fixerTest($expected, $input, $fixStatement);
  43. }
  44. public function provideFixCases(): array
  45. {
  46. return [
  47. [
  48. '<?php while ($x) { break; }',
  49. ],
  50. [
  51. '<?php while ($x) { while ($y) { break 2; } }',
  52. '<?php while ($x) { while ($y) { break (2); } }',
  53. ],
  54. [
  55. '<?php while ($x) { while ($y) { break 2; } }',
  56. '<?php while ($x) { while ($y) { break(2); } }',
  57. ],
  58. [
  59. '<?php while ($x) { continue; }',
  60. ],
  61. [
  62. '<?php while ($x) { while ($y) { continue 2; } }',
  63. '<?php while ($x) { while ($y) { continue (2); } }',
  64. ],
  65. [
  66. '<?php while ($x) { while ($y) { continue 2; } }',
  67. '<?php while ($x) { while ($y) { continue(2); } }',
  68. ],
  69. [
  70. '<?php
  71. clone $object;
  72. ',
  73. ],
  74. [
  75. '<?php
  76. clone new Foo();
  77. ',
  78. ],
  79. [
  80. '<?php
  81. $var = clone ($obj1 ?: $obj2);
  82. ',
  83. ],
  84. [
  85. '<?php
  86. $var = clone ($obj1 ? $obj1->getSubject() : $obj2);
  87. ',
  88. ],
  89. [
  90. '<?php
  91. clone $object;
  92. ',
  93. '<?php
  94. clone ($object);
  95. ',
  96. ],
  97. [
  98. '<?php
  99. clone new Foo();
  100. ',
  101. '<?php
  102. clone (new Foo());
  103. ',
  104. ],
  105. [
  106. '<?php
  107. foo(clone $a);
  108. foo(clone $a, 1);
  109. $a = $b ? clone $b : $c;
  110. ',
  111. '<?php
  112. foo(clone($a));
  113. foo(clone($a), 1);
  114. $a = $b ? clone($b) : $c;
  115. ',
  116. ],
  117. [
  118. '<?php
  119. echo "foo";
  120. print "foo";
  121. ',
  122. ],
  123. [
  124. '<?php
  125. echo (1 + 2) . $foo;
  126. print (1 + 2) . $foo;
  127. ',
  128. ],
  129. [
  130. '<?php
  131. echo (1 + 2) * 10, "\n";
  132. ',
  133. ],
  134. [
  135. '<?php echo (1 + 2) * 10, "\n" ?>',
  136. ],
  137. [
  138. '<?php echo "foo" ?>',
  139. '<?php echo ("foo") ?>',
  140. ],
  141. [
  142. '<?php print "foo" ?>',
  143. '<?php print ("foo") ?>',
  144. ],
  145. [
  146. '<?php
  147. echo "foo";
  148. print "foo";
  149. ',
  150. '<?php
  151. echo ("foo");
  152. print ("foo");
  153. ',
  154. ],
  155. [
  156. '<?php
  157. echo "foo";
  158. print "foo";
  159. ',
  160. '<?php
  161. echo("foo");
  162. print("foo");
  163. ',
  164. ],
  165. [
  166. '<?php
  167. echo 2;
  168. print 2;
  169. ',
  170. '<?php
  171. echo(2);
  172. print(2);
  173. ',
  174. ],
  175. [
  176. '<?php
  177. echo $a ? $b : $c;
  178. echo ($a ? $b : $c) ? $d : $e;
  179. echo 10 * (2 + 3);
  180. echo ("foo"), ("bar");
  181. echo my_awesome_function("foo");
  182. echo $this->getOutput(1);
  183. ',
  184. '<?php
  185. echo ($a ? $b : $c);
  186. echo ($a ? $b : $c) ? $d : $e;
  187. echo 10 * (2 + 3);
  188. echo ("foo"), ("bar");
  189. echo my_awesome_function("foo");
  190. echo $this->getOutput(1);
  191. ',
  192. ],
  193. [
  194. '<?php
  195. return "prod";
  196. ',
  197. ],
  198. [
  199. '<?php
  200. return (1 + 2) * 10;
  201. ',
  202. ],
  203. [
  204. '<?php
  205. return (1 + 2) * 10;
  206. ',
  207. '<?php
  208. return ((1 + 2) * 10);
  209. ',
  210. ],
  211. [
  212. '<?php
  213. return "prod";
  214. ',
  215. '<?php
  216. return ("prod");
  217. ',
  218. ],
  219. [
  220. '<?php
  221. return $x;
  222. ',
  223. '<?php
  224. return($x);
  225. ',
  226. ],
  227. [
  228. '<?php
  229. return 2;
  230. ',
  231. '<?php
  232. return(2);
  233. ',
  234. ],
  235. [
  236. '<?php
  237. return 2?>
  238. ',
  239. '<?php
  240. return(2)?>
  241. ',
  242. ],
  243. [
  244. '<?php
  245. switch ($a) {
  246. case "prod":
  247. break;
  248. }
  249. ',
  250. ],
  251. [
  252. '<?php
  253. switch ($a) {
  254. case "prod":
  255. break;
  256. }
  257. ',
  258. '<?php
  259. switch ($a) {
  260. case ("prod"):
  261. break;
  262. }
  263. ',
  264. 'switch_case',
  265. ],
  266. [
  267. '<?php
  268. switch ($a) {
  269. case $x;
  270. }
  271. ',
  272. '<?php
  273. switch ($a) {
  274. case($x);
  275. }
  276. ',
  277. ],
  278. [
  279. '<?php
  280. switch ($a) {
  281. case 2;
  282. }
  283. ',
  284. '<?php
  285. switch ($a) {
  286. case(2);
  287. }
  288. ',
  289. ],
  290. [
  291. '<?php
  292. $a = 5.1;
  293. $b = 1.0;
  294. switch($a) {
  295. case (int) $a < 1 : {
  296. echo "leave alone";
  297. break;
  298. }
  299. case $a < 2/* test */: {
  300. echo "fix 1";
  301. break;
  302. }
  303. case 3 : {
  304. echo "fix 2";
  305. break;
  306. }
  307. case /**//**/ // test
  308. 4
  309. /**///
  310. /**/: {
  311. echo "fix 3";
  312. break;
  313. }
  314. case ((int)$b) + 4.1: {
  315. echo "fix 4";
  316. break;
  317. }
  318. case ($b + 1) * 2: {
  319. echo "leave alone";
  320. break;
  321. }
  322. }
  323. ',
  324. '<?php
  325. $a = 5.1;
  326. $b = 1.0;
  327. switch($a) {
  328. case (int) $a < 1 : {
  329. echo "leave alone";
  330. break;
  331. }
  332. case ($a < 2)/* test */: {
  333. echo "fix 1";
  334. break;
  335. }
  336. case (3) : {
  337. echo "fix 2";
  338. break;
  339. }
  340. case /**/(/**/ // test
  341. 4
  342. /**/)//
  343. /**/: {
  344. echo "fix 3";
  345. break;
  346. }
  347. case (((int)$b) + 4.1): {
  348. echo "fix 4";
  349. break;
  350. }
  351. case ($b + 1) * 2: {
  352. echo "leave alone";
  353. break;
  354. }
  355. }
  356. ',
  357. 'switch_case',
  358. ],
  359. [
  360. '<?php while ($x) { while ($y) { break#
  361. #
  362. 2#
  363. #
  364. ; } }',
  365. '<?php while ($x) { while ($y) { break#
  366. (#
  367. 2#
  368. )#
  369. ; } }',
  370. ],
  371. [
  372. '<?php
  373. function foo() { yield "prod"; }
  374. ',
  375. ],
  376. [
  377. '<?php
  378. function foo() { yield (1 + 2) * 10; }
  379. ',
  380. ],
  381. [
  382. '<?php
  383. function foo() { yield (1 + 2) * 10; }
  384. ',
  385. '<?php
  386. function foo() { yield ((1 + 2) * 10); }
  387. ',
  388. ],
  389. [
  390. '<?php
  391. function foo() { yield "prod"; }
  392. ',
  393. '<?php
  394. function foo() { yield ("prod"); }
  395. ',
  396. ],
  397. [
  398. '<?php
  399. function foo() { yield 2; }
  400. ',
  401. '<?php
  402. function foo() { yield(2); }
  403. ',
  404. ],
  405. [
  406. '<?php
  407. function foo() { $a = (yield $x); }
  408. ',
  409. '<?php
  410. function foo() { $a = (yield($x)); }
  411. ',
  412. ],
  413. [
  414. '<?php
  415. $var = clone ($obj1->getSubject() ?? $obj2);
  416. ',
  417. ],
  418. ];
  419. }
  420. /**
  421. * @dataProvider provideFixYieldFromCases
  422. */
  423. public function testFixYieldFrom(string $expected, ?string $input = null): void
  424. {
  425. $this->fixer->configure(['statements' => ['yield_from']]);
  426. $this->doTest($expected, $input);
  427. }
  428. public function provideFixYieldFromCases(): array
  429. {
  430. return [
  431. [
  432. '<?php
  433. function foo1() { yield from "prod"; }
  434. ',
  435. ],
  436. [
  437. '<?php
  438. function foo2() { yield from (1 + 2) * 10; }
  439. function foo3() { $a = (yield($x)); }
  440. ',
  441. ],
  442. [
  443. '<?php
  444. function foo4() { yield from (1 + 2) * 10; }
  445. ',
  446. '<?php
  447. function foo4() { yield from ((1 + 2) * 10); }
  448. ',
  449. ],
  450. [
  451. '<?php
  452. function foo5() { yield from "prod"; }
  453. function foo6() { $a = (yield($x)); }
  454. ',
  455. '<?php
  456. function foo5() { yield from ("prod"); }
  457. function foo6() { $a = (yield($x)); }
  458. ',
  459. ],
  460. [
  461. '<?php
  462. function foo7() { yield from 2; }
  463. ',
  464. '<?php
  465. function foo7() { yield from(2); }
  466. ',
  467. ],
  468. [
  469. '<?php
  470. function foo8() { $a = (yield from $x); }
  471. ',
  472. '<?php
  473. function foo8() { $a = (yield from($x)); }
  474. ',
  475. ],
  476. ];
  477. }
  478. /**
  479. * @dataProvider provideFix81Cases
  480. * @requires PHP 8.1
  481. */
  482. public function testFix81(string $expected, ?string $input = null): void
  483. {
  484. $this->fixer->configure(['statements' => ['switch_case']]);
  485. $this->doTest($expected, $input);
  486. }
  487. public function provideFix81Cases(): \Generator
  488. {
  489. yield 'enums' => [
  490. '<?php
  491. enum Suit {
  492. case Hearts ;
  493. case Diamonds ;
  494. case Clubs ;
  495. case Spades ;
  496. }
  497. enum UserStatus: string {
  498. case Pending = "P";
  499. case Active = "A";
  500. case Suspended = "S";
  501. case CanceledByUser = "C" ;
  502. }
  503. ',
  504. ];
  505. }
  506. private function fixerTest(string $expected, ?string $input = null, ?string $fixStatement = null, bool $legacy = false): void
  507. {
  508. // Default config. Fixes all statements.
  509. $this->doTest($expected, $input);
  510. $this->fixer->configure($legacy ? self::$defaultStatements : ['statements' => self::$defaultStatements]);
  511. $this->doTest($expected, $input);
  512. // Empty array config. Should not fix anything.
  513. $this->fixer->configure([]);
  514. $this->doTest($expected, null);
  515. // Test with only one statement
  516. foreach (self::$defaultStatements as $statement) {
  517. $withInput = false;
  518. if (null !== $input && (null === $fixStatement || $fixStatement === $statement)) {
  519. foreach (explode('_', $statement) as $singleStatement) {
  520. if (str_contains($input, $singleStatement)) {
  521. $withInput = true;
  522. break;
  523. }
  524. }
  525. }
  526. $this->fixer->configure($legacy ? [$statement] : ['statements' => [$statement]]);
  527. $this->doTest(
  528. $expected,
  529. $withInput ? $input : null
  530. );
  531. }
  532. }
  533. }