YodaStyleFixerTest.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215
  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\ConfigurationException\InvalidFixerConfigurationException;
  14. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  15. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  16. /**
  17. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  18. *
  19. * @internal
  20. *
  21. * @covers \PhpCsFixer\Fixer\ControlStructure\YodaStyleFixer
  22. *
  23. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\ControlStructure\YodaStyleFixer>
  24. *
  25. * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\ControlStructure\YodaStyleFixer
  26. */
  27. final class YodaStyleFixerTest extends AbstractFixerTestCase
  28. {
  29. /**
  30. * @param array<string, mixed> $extraConfig
  31. *
  32. * @dataProvider provideFixCases
  33. */
  34. public function testFix(string $expected, ?string $input = null, array $extraConfig = []): void
  35. {
  36. $this->fixer->configure(['equal' => true, 'identical' => true] + $extraConfig);
  37. $this->doTest($expected, $input);
  38. }
  39. /**
  40. * Test with the inverse config.
  41. *
  42. * @param array<string, mixed> $extraConfig
  43. *
  44. * @dataProvider provideFixCases
  45. */
  46. public function testFixInverse(string $expected, ?string $input = null, array $extraConfig = []): void
  47. {
  48. $this->fixer->configure(['equal' => false, 'identical' => false] + $extraConfig);
  49. if (null === $input) {
  50. $this->doTest($expected);
  51. } else {
  52. $this->doTest($input, $expected);
  53. }
  54. }
  55. public static function provideFixCases(): iterable
  56. {
  57. yield [
  58. '<?php $a = 1 + ($b + $c) === true ? 1 : 2;',
  59. null,
  60. ['always_move_variable' => true],
  61. ];
  62. yield [
  63. '<?php $a = true === ($b + $c) ? 1 : 2;',
  64. '<?php $a = ($b + $c) === true ? 1 : 2;',
  65. ['always_move_variable' => true],
  66. ];
  67. yield [
  68. '<?php
  69. if ((1 === $a) === 1) {
  70. return;
  71. }',
  72. '<?php
  73. if (($a === 1) === 1) {
  74. return;
  75. }',
  76. ['always_move_variable' => false],
  77. ];
  78. yield [
  79. '<?php
  80. if (true === (1 !== $foo[0])) {
  81. return;
  82. }',
  83. '<?php
  84. if (($foo[0] !== 1) === true) {
  85. return;
  86. }',
  87. ['always_move_variable' => true],
  88. ];
  89. yield [
  90. '<?php return 1 !== $a [$b];',
  91. '<?php return $a [$b] !== 1;',
  92. ];
  93. yield [
  94. '<?= 1 === $a ? 5 : 7;',
  95. '<?= $a === 1 ? 5 : 7;',
  96. ];
  97. yield [
  98. '<?php print 1 === 1343;',
  99. ];
  100. yield [
  101. '<?php
  102. echo 3 === $a ? 2 : 4;
  103. ',
  104. '<?php
  105. echo $a === 3 ? 2 : 4;
  106. ',
  107. ];
  108. yield [
  109. '<?php 1 === foo($a) ? 1 : 2;',
  110. '<?php foo($a) === 1 ? 1 : 2;',
  111. ];
  112. yield [
  113. '<?php 1 === $a::$a ? 1 : 2;',
  114. '<?php $a::$a === 1 ? 1 : 2;',
  115. ];
  116. yield [
  117. '<?php 1 === (bool) $a ? 8 : 7;',
  118. '<?php (bool) $a === 1 ? 8 : 7;',
  119. ];
  120. yield [
  121. '<?php 1 === new $a ? 1 : 2;',
  122. '<?php new $a === 1 ? 1 : 2;',
  123. ];
  124. yield [
  125. '<?php 1 === "a".$a ? 5 : 6;',
  126. '<?php "a".$a === 1 ? 5 : 6;',
  127. ];
  128. yield [
  129. '<?php 1 === __DIR__.$a ? 5 : 6;',
  130. '<?php __DIR__.$a === 1 ? 5 : 6;',
  131. ];
  132. yield [
  133. '<?php 1 === $a.$b ? 5 : 6;',
  134. '<?php $a.$b === 1 ? 5 : 6;',
  135. ];
  136. yield [
  137. '<?php echo 1 === (object) $a ? 8 : 7;',
  138. '<?php echo (object) $a === 1 ? 8 : 7;',
  139. ];
  140. yield [
  141. '<?php echo 1 === (int) $a ? 8 : 7;',
  142. '<?php echo (int) $a === 1 ? 8 : 7;',
  143. ];
  144. yield [
  145. '<?php echo 1 === (float) $a ? 8 : 7;',
  146. '<?php echo (float) $a === 1 ? 8 : 7;',
  147. ];
  148. yield [
  149. '<?php echo 1 === (string) $a ? 8 : 7;',
  150. '<?php echo (string) $a === 1 ? 8 : 7;',
  151. ];
  152. yield [
  153. '<?php echo 1 === (array) $a ? 8 : 7;',
  154. '<?php echo (array) $a === 1 ? 8 : 7;',
  155. ];
  156. yield [
  157. '<?php echo 1 === (bool) $a ? 8 : 7;',
  158. '<?php echo (bool) $a === 1 ? 8 : 7;',
  159. ];
  160. yield [
  161. '<?php
  162. if ($a = true === $obj instanceof A) {
  163. echo \'A\';
  164. }',
  165. '<?php
  166. if ($a = $obj instanceof A === true) {
  167. echo \'A\';
  168. }',
  169. ];
  170. yield [
  171. '<?php echo 1 === !!$a ? 8 : 7;',
  172. '<?php echo !!$a === 1 ? 8 : 7;',
  173. ];
  174. yield [
  175. '<?php 1 === new $a ? 1 : 2;',
  176. '<?php new $a === 1 ? 1 : 2;',
  177. ];
  178. yield [
  179. '<?php $a = 1 === new b ? 1 : 2;',
  180. '<?php $a = new b === 1 ? 1 : 2;',
  181. ];
  182. yield [
  183. '<?php $a = 1 === empty($a) ? 1 : 2;',
  184. '<?php $a = empty($a) === 1 ? 1 : 2;',
  185. ];
  186. yield [
  187. '<?php $b = 1 === clone $a ? 5 : 9;',
  188. '<?php $b = clone $a === 1 ? 5 : 9;',
  189. ];
  190. yield [
  191. '<?php while(1 === $a ? 1 : 2){};',
  192. '<?php while($a === 1 ? 1 : 2){};',
  193. ];
  194. yield [
  195. '<?php switch(1 === $a){
  196. case true: echo 1;
  197. };',
  198. '<?php switch($a === 1){
  199. case true: echo 1;
  200. };',
  201. ];
  202. yield [
  203. '<?php echo 1 === $a ? 1 : 2;',
  204. '<?php echo $a === 1 ? 1 : 2;',
  205. ];
  206. // Don't fix cases.
  207. yield ['<?php $a = 1 === 1;'];
  208. yield ['<?php $b = $b === $c;'];
  209. yield ['<?php $c = $$b === $$c;'];
  210. yield ['<?php $d = count($this->array[$var]) === $a;'];
  211. yield ['<?php $e = $a === count($this->array[$var]);'];
  212. yield ['<?php $f = ($a123 & self::MY_BITMASK) === $a;'];
  213. yield ['<?php $g = $a === ($a456 & self::MY_BITMASK);'];
  214. yield ['<?php $h = $this->getStuff() === $myVariable;'];
  215. yield ['<?php $i = $myVariable === $this->getStuff();'];
  216. yield ['<?php $j = 2 * $myVar % 3 === $a;'];
  217. yield ['<?php return $k === 2 * $myVar % 3;'];
  218. yield ['<?php $l = $c > 2;'];
  219. yield ['<?php return $this->myObject1->{$index}+$b === "";'];
  220. yield ['<?php return $m[2]+1 == 2;'];
  221. yield ['<?php return $foo === $bar[$baz][1];'];
  222. yield ['<?php $a = $b[$key]["1"] === $c["2"];'];
  223. yield ['<?php return $foo->$a === $foo->$b->$c;'];
  224. yield ['<?php return $x === 2 - 1;'];
  225. yield ['<?php return $x === 2-1;'];
  226. // https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/pull/693
  227. yield ['<?php return array(2) == $o;'];
  228. yield ['<?php return $p == array(2);'];
  229. yield ['<?php return $p == array("2");'];
  230. yield ['<?php return $p == array(TWO);'];
  231. yield ['<?php return $p == array(array());'];
  232. yield ['<?php return $p == [[]];'];
  233. yield ['<?php return array($q) == $a;'];
  234. yield ['<?php return $r == array($a);'];
  235. yield ['<?php $s = ((array(2))) == $a;'];
  236. yield ['<?php $t = $a == ((array(2)));'];
  237. yield ['<?php list($a) = $c === array(1) ? $b : $d;'];
  238. yield ['<?php $b = 7 === list($a) = [7];'];
  239. yield ['<?php $a = function(){} === array(0);'];
  240. yield ['<?php $z = $n == list($a) = $b;'];
  241. yield ['<?php return $n == list($a) = $b;'];
  242. // Fix cases.
  243. yield 'Array destruct by ternary.' => [
  244. '<?php list($a) = 11 === $c ? $b : $d;',
  245. '<?php list($a) = $c === 11 ? $b : $d;',
  246. ];
  247. yield 'Less spacing.' => [
  248. '<?php $z=2==$a;$b=$c>1&&$c<=10;',
  249. '<?php $z=$a==2;$b=$c>1&&$c<=10;',
  250. ];
  251. yield 'Comments.' => [
  252. '<?php $z = /**/ /**/2/**/ /**/
  253. # aa
  254. /**/==/**/$a/***/;',
  255. '<?php $z = /**/ /**/$a/**/ /**/
  256. # aa
  257. /**/==/**/2/***/;',
  258. ];
  259. yield [
  260. '<?php return 2 == ($a)?>',
  261. ];
  262. yield [
  263. '<?php return ($a) == 2?>',
  264. ];
  265. yield [
  266. '<?php return 2 == ($a)?>',
  267. '<?php return ($a) == 2?>',
  268. ['always_move_variable' => true],
  269. ];
  270. yield [
  271. '<?php $a = ($c === ((null === $b)));',
  272. '<?php $a = ($c === (($b === null)));',
  273. ];
  274. yield [
  275. '<?php return null == $a[2];',
  276. '<?php return $a[2] == null;',
  277. ];
  278. yield [
  279. '<?php return "" === $this->myArray[$index];',
  280. '<?php return $this->myArray[$index] === "";',
  281. ];
  282. yield [
  283. '<?php return "" === $this->myArray[$index]->/*1*//*2*//*3*/a;',
  284. '<?php return $this->myArray[$index]->/*1*//*2*//*3*/a === "";',
  285. ];
  286. yield [
  287. '<?php return "" === $this->myArray[$index]->a;',
  288. '<?php return $this->myArray[$index]->a === "";',
  289. ];
  290. yield [
  291. '<?php return "" === $this->myObject2-> {$index};',
  292. '<?php return $this->myObject2-> {$index} === "";',
  293. ];
  294. yield [
  295. '<?php return "" === $this->myObject3->{$index}->a;',
  296. '<?php return $this->myObject3->{$index}->a === "";',
  297. ];
  298. yield [
  299. '<?php return "" === $this->myObject4->{$index}->{$index}->a;',
  300. '<?php return $this->myObject4->{$index}->{$index}->a === "";',
  301. ];
  302. yield [
  303. '<?php return "" === $this->myObject4->$index->a;',
  304. '<?php return $this->myObject4->$index->a === "";',
  305. ];
  306. yield [
  307. '<?php return self::MY_CONST === self::$myVariable;',
  308. '<?php return self::$myVariable === self::MY_CONST;',
  309. ];
  310. yield [
  311. '<?php return \A\B\C::MY_CONST === \A\B\C::$myVariable;',
  312. '<?php return \A\B\C::$myVariable === \A\B\C::MY_CONST;',
  313. ];
  314. yield [
  315. '<?php $a = 1 == $$a?>',
  316. '<?php $a = $$a == 1?>',
  317. ];
  318. yield 'Nested case' => [
  319. '<?php return null === $a[0 === $b ? $c : $d];',
  320. '<?php return $a[$b === 0 ? $c : $d] === null;',
  321. ];
  322. yield [
  323. '<?php return null === $this->{null === $a ? "a" : "b"};',
  324. '<?php return $this->{$a === null ? "a" : "b"} === null;',
  325. ];
  326. yield 'Complex code sample.' => [
  327. '<?php
  328. if ($a == $b) {
  329. return null === $b ? (null === $a ? 0 : 0 === $a->b) : 0 === $b->a;
  330. } else {
  331. if ($c === (null === $b)) {
  332. return false === $d;
  333. }
  334. }',
  335. '<?php
  336. if ($a == $b) {
  337. return $b === null ? ($a === null ? 0 : $a->b === 0) : $b->a === 0;
  338. } else {
  339. if ($c === ($b === null)) {
  340. return $d === false;
  341. }
  342. }',
  343. ];
  344. yield [
  345. '<?php $b = list($a) = 7 === [7];', // makes no sense, but valid PHP syntax
  346. '<?php $b = list($a) = [7] === 7;',
  347. ];
  348. yield [
  349. '<?php $a = 1 === function(){};',
  350. '<?php $a = function(){} === 1;',
  351. ];
  352. yield [
  353. '<?php
  354. $z#1
  355. #2
  356. =
  357. #3
  358. 1#4
  359. #5
  360. ===#6
  361. #7
  362. $a#8
  363. #9
  364. ;#10',
  365. '<?php
  366. $z#1
  367. #2
  368. =
  369. #3
  370. $a#4
  371. #5
  372. ===#6
  373. #7
  374. 1#8
  375. #9
  376. ;#10',
  377. ];
  378. yield [
  379. '<?php $i = 2 === $this/*a*//*b*//*c*//*d*//*e*//*f*/->getStuff();',
  380. '<?php $i = $this/*a*//*b*//*c*//*d*//*e*//*f*/->getStuff() === 2;',
  381. ];
  382. yield [
  383. '<?php return "" === $this->myObject5->{$index}->/*1*//*2*/b;',
  384. '<?php return $this->myObject5->{$index}->/*1*//*2*/b === "";',
  385. ];
  386. yield [
  387. '<?php
  388. function hello() {}
  389. 1 === $a ? b() : c();
  390. ',
  391. '<?php
  392. function hello() {}
  393. $a === 1 ? b() : c();
  394. ',
  395. ];
  396. yield [
  397. '<?php
  398. class A{}
  399. 1 === $a ? b() : c();
  400. ',
  401. '<?php
  402. class A{}
  403. $a === 1 ? b() : c();
  404. ',
  405. ];
  406. yield [
  407. '<?php
  408. function foo() {
  409. foreach ($arr as $key => $value) {
  410. false !== uniqid() ? 1 : 2;
  411. }
  412. false !== uniqid() ? 1 : 2;
  413. }',
  414. '<?php
  415. function foo() {
  416. foreach ($arr as $key => $value) {
  417. uniqid() !== false ? 1 : 2;
  418. }
  419. uniqid() !== false ? 1 : 2;
  420. }',
  421. ];
  422. yield [
  423. '<?php false === $a = array();',
  424. ];
  425. yield [
  426. '<?php $e = count($this->array[$var]) === $a;',
  427. '<?php $e = $a === count($this->array[$var]);',
  428. ['always_move_variable' => true],
  429. ];
  430. yield [
  431. '<?php $i = $this->getStuff() === $myVariable;',
  432. '<?php $i = $myVariable === $this->getStuff();',
  433. ['always_move_variable' => true],
  434. ];
  435. yield [
  436. '<?php $e = count($this->array[$var]) === $a;',
  437. '<?php $e = $a === count($this->array[$var]);',
  438. ['always_move_variable' => true],
  439. ];
  440. yield [
  441. '<?php $g = ($a789 & self::MY_BITMASK) === $a;',
  442. null,
  443. ['always_move_variable' => true],
  444. ];
  445. yield [
  446. '<?php return $myVar + 2 === $k;',
  447. '<?php return $k === $myVar + 2;',
  448. ['always_move_variable' => true],
  449. ];
  450. yield [
  451. '<?php return $myVar . $b === $k;',
  452. '<?php return $k === $myVar . $b;',
  453. ['always_move_variable' => true],
  454. ];
  455. yield [
  456. '<?php return $myVar - 2 === $k;',
  457. '<?php return $k === $myVar - 2;',
  458. ['always_move_variable' => true],
  459. ];
  460. yield [
  461. '<?php return $myVar * 2 === $k;',
  462. '<?php return $k === $myVar * 2;',
  463. ['always_move_variable' => true],
  464. ];
  465. yield [
  466. '<?php return $myVar / 2 === $k;',
  467. '<?php return $k === $myVar / 2;',
  468. ['always_move_variable' => true],
  469. ];
  470. yield [
  471. '<?php return $myVar % 2 === $k;',
  472. '<?php return $k === $myVar % 2;',
  473. ['always_move_variable' => true],
  474. ];
  475. yield [
  476. '<?php return $myVar ** 2 === $k;',
  477. '<?php return $k === $myVar ** 2;',
  478. ['always_move_variable' => true],
  479. ];
  480. yield [
  481. '<?php return $myVar < 2 === $k;',
  482. '<?php return $k === $myVar < 2;',
  483. ['always_move_variable' => true],
  484. ];
  485. yield [
  486. '<?php return $myVar > 2 === $k;',
  487. '<?php return $k === $myVar > 2;',
  488. ['always_move_variable' => true],
  489. ];
  490. yield [
  491. '<?php return $myVar <= 2 === $k;',
  492. '<?php return $k === $myVar <= 2;',
  493. ['always_move_variable' => true],
  494. ];
  495. yield [
  496. '<?php return $myVar >= 2 === $k;',
  497. '<?php return $k === $myVar >= 2;',
  498. ['always_move_variable' => true],
  499. ];
  500. yield [
  501. '<?php return $myVar . 2 === $k;',
  502. '<?php return $k === $myVar . 2;',
  503. ['always_move_variable' => true],
  504. ];
  505. yield [
  506. '<?php return $myVar << 2 === $k;',
  507. '<?php return $k === $myVar << 2;',
  508. ['always_move_variable' => true],
  509. ];
  510. yield [
  511. '<?php return $myVar >> 2 === $k;',
  512. '<?php return $k === $myVar >> 2;',
  513. ['always_move_variable' => true],
  514. ];
  515. yield [
  516. '<?php return !$myVar === $k;',
  517. '<?php return $k === !$myVar;',
  518. ['always_move_variable' => true],
  519. ];
  520. yield [
  521. '<?php return $myVar instanceof Foo === $k;',
  522. '<?php return $k === $myVar instanceof Foo;',
  523. ['always_move_variable' => true],
  524. ];
  525. yield [
  526. '<?php return (bool) $myVar === $k;',
  527. '<?php return $k === (bool) $myVar;',
  528. ['always_move_variable' => true],
  529. ];
  530. yield [
  531. '<?php return (int) $myVar === $k;',
  532. '<?php return $k === (int) $myVar;',
  533. ['always_move_variable' => true],
  534. ];
  535. yield [
  536. '<?php return (float) $myVar === $k;',
  537. '<?php return $k === (float) $myVar;',
  538. ['always_move_variable' => true],
  539. ];
  540. yield [
  541. '<?php return (string) $myVar === $k;',
  542. '<?php return $k === (string) $myVar;',
  543. ['always_move_variable' => true],
  544. ];
  545. yield [
  546. '<?php return (array) $myVar === $k;',
  547. '<?php return $k === (array) $myVar;',
  548. ['always_move_variable' => true],
  549. ];
  550. yield [
  551. '<?php return (object) $myVar === $k;',
  552. '<?php return $k === (object) $myVar;',
  553. ['always_move_variable' => true],
  554. ];
  555. yield [
  556. '<?php $a = null === foo();',
  557. '<?php $a = foo() === null;',
  558. ];
  559. yield [
  560. '<?php $a = \'foo\' === foo();',
  561. '<?php $a = foo() === \'foo\';',
  562. ];
  563. yield [
  564. '<?php $a = "foo" === foo();',
  565. '<?php $a = foo() === "foo";',
  566. ];
  567. yield [
  568. '<?php $a = 1 === foo();',
  569. '<?php $a = foo() === 1;',
  570. ];
  571. yield [
  572. '<?php $a = 1.2 === foo();',
  573. '<?php $a = foo() === 1.2;',
  574. ];
  575. yield [
  576. '<?php $a = true === foo();',
  577. '<?php $a = foo() === true;',
  578. ];
  579. yield [
  580. '<?php $a = false === foo();',
  581. '<?php $a = foo() === false;',
  582. ];
  583. yield [
  584. '<?php $a = -1 === reset($foo);',
  585. '<?php $a = reset($foo) === -1;',
  586. ];
  587. yield [
  588. '<?php $a = - 1 === reset($foo);',
  589. '<?php $a = reset($foo) === - 1;',
  590. ];
  591. yield [
  592. '<?php $a = -/* bar */1 === reset($foo);',
  593. '<?php $a = reset($foo) === -/* bar */1;',
  594. ];
  595. yield [
  596. '<?php $a %= 4 === $b ? 2 : 3;',
  597. '<?php $a %= $b === 4 ? 2 : 3;',
  598. ];
  599. yield [
  600. '<?php return array() === $array;',
  601. '<?php return $array === array();',
  602. ];
  603. yield [
  604. '<?php return [] === $array;',
  605. '<?php return $array === [];',
  606. ];
  607. yield [
  608. '<?php return array(/* foo */) === $array;',
  609. '<?php return $array === array(/* foo */);',
  610. ];
  611. yield [
  612. '<?php return [
  613. // 1
  614. ] === $array;',
  615. '<?php return $array === [
  616. // 1
  617. ];',
  618. ];
  619. yield [
  620. '<?php $a = $b = null === $c;',
  621. '<?php $a = $b = $c === null;',
  622. ];
  623. $template = '<?php $a = ($b + $c) %s 1 === true ? 1 : 2;';
  624. $operators = ['||', '&&'];
  625. foreach ($operators as $operator) {
  626. yield [
  627. \sprintf($template, $operator),
  628. null,
  629. ['always_move_variable' => true],
  630. ];
  631. }
  632. $assignmentOperators = ['=', '**=', '*=', '|=', '+=', '-=', '^=', '<<=', '>>=', '&=', '.=', '/=', '%=', '??='];
  633. $logicalOperators = ['xor', 'or', 'and', '||', '&&', '??'];
  634. foreach ([...$assignmentOperators, ...$logicalOperators] as $operator) {
  635. yield [
  636. \sprintf('<?php $a %s 4 === $b ? 2 : 3;', $operator),
  637. \sprintf('<?php $a %s $b === 4 ? 2 : 3;', $operator),
  638. ];
  639. }
  640. foreach ($assignmentOperators as $operator) {
  641. yield [
  642. \sprintf('<?php 1 === $x %s 2;', $operator),
  643. ];
  644. }
  645. yield ['<?php $a = $b + 1 <=> $d;'];
  646. yield [
  647. '<?php $a = new class(10) extends SomeClass implements SomeInterface {} === $a;/**/',
  648. ];
  649. yield [
  650. '<?php $a = $b ?? 1 ?? 2 == $d;',
  651. '<?php $a = $b ?? 1 ?? $d == 2;',
  652. ];
  653. yield [
  654. '<?php $a = 1 === new class(10) extends SomeClass implements SomeInterface {};/**/',
  655. '<?php $a = new class(10) extends SomeClass implements SomeInterface {} === 1;/**/',
  656. ];
  657. yield [
  658. '<?php
  659. function a() {
  660. for ($i = 1; $i <= 3; $i++) {
  661. echo yield 1 === $i ? 1 : 2;
  662. }
  663. }
  664. ',
  665. '<?php
  666. function a() {
  667. for ($i = 1; $i <= 3; $i++) {
  668. echo yield $i === 1 ? 1 : 2;
  669. }
  670. }
  671. ',
  672. ];
  673. yield [
  674. '<?php function test() {return yield 1 !== $a [$b];};',
  675. '<?php function test() {return yield $a [$b] !== 1;};',
  676. ];
  677. yield [
  678. '<?php function test() {return yield 1 === $a;};',
  679. '<?php function test() {return yield $a === 1;};',
  680. ];
  681. yield [
  682. '<?php
  683. $a = 1;
  684. switch ($a) {
  685. case 1 === $a:
  686. echo 123;
  687. break;
  688. }
  689. ',
  690. '<?php
  691. $a = 1;
  692. switch ($a) {
  693. case $a === 1:
  694. echo 123;
  695. break;
  696. }
  697. ',
  698. ];
  699. yield 'require' => [
  700. '<?php require 1 === $var ? "A.php" : "B.php";',
  701. '<?php require $var === 1 ? "A.php" : "B.php";',
  702. ];
  703. yield 'require_once' => [
  704. '<?php require_once 1 === $var ? "A.php" : "B.php";',
  705. '<?php require_once $var === 1 ? "A.php" : "B.php";',
  706. ];
  707. yield 'include' => [
  708. '<?php include 1 === $var ? "A.php" : "B.php";',
  709. '<?php include $var === 1 ? "A.php" : "B.php";',
  710. ];
  711. yield 'include_once' => [
  712. '<?php include_once 1 === $var ? "A.php" : "B.php";',
  713. '<?php include_once $var === 1 ? "A.php" : "B.php";',
  714. ];
  715. yield 'yield from' => [
  716. '<?php function test() {return yield from 1 === $a ? $c : $d;};',
  717. '<?php function test() {return yield from $a === 1 ? $c : $d;};',
  718. ];
  719. yield [
  720. '<?php if (1_000 === $b);',
  721. '<?php if ($b === 1_000);',
  722. ];
  723. yield [
  724. '<?php fn() => $c === array(1) ? $b : $d;',
  725. null,
  726. [
  727. 'less_and_greater' => false,
  728. ],
  729. ];
  730. yield [
  731. '<?php $a ??= 4 === $b ? 2 : 3;',
  732. '<?php $a ??= $b === 4 ? 2 : 3;',
  733. ];
  734. }
  735. /**
  736. * @dataProvider provideLessGreaterCases
  737. */
  738. public function testFixLessGreater(string $expected, string $input): void
  739. {
  740. $this->fixer->configure(['less_and_greater' => true]);
  741. $this->doTest($expected, $input);
  742. }
  743. /**
  744. * Test with the inverse config.
  745. *
  746. * @dataProvider provideLessGreaterCases
  747. */
  748. public function testFixLessGreaterInverse(string $expected, string $input): void
  749. {
  750. $this->fixer->configure(['less_and_greater' => false]);
  751. $this->doTest($input, $expected);
  752. }
  753. public static function provideLessGreaterCases(): iterable
  754. {
  755. yield [
  756. '<?php $a = 3 <= $b;',
  757. '<?php $a = $b >= 3;',
  758. ];
  759. yield [
  760. '<?php $a = 3 > $b;',
  761. '<?php $a = $b < 3;',
  762. ];
  763. yield [
  764. '<?php $a = (3 > $b) || $d;',
  765. '<?php $a = ($b < 3) || $d;',
  766. ];
  767. }
  768. public function testComplexConfiguration(): void
  769. {
  770. $this->fixer->configure([
  771. 'equal' => null,
  772. 'identical' => true,
  773. 'less_and_greater' => false,
  774. ]);
  775. $this->doTest(
  776. '<?php
  777. $a = 1 === $b;
  778. $b = $c != 1;
  779. $c = $c > 3;
  780. ',
  781. '<?php
  782. $a = $b === 1;
  783. $b = $c != 1;
  784. $c = $c > 3;
  785. '
  786. );
  787. }
  788. /**
  789. * @param _AutogeneratedInputConfiguration $config
  790. *
  791. * @dataProvider provideInvalidConfigCases
  792. */
  793. public function testInvalidConfig(array $config, string $expectedMessage): void
  794. {
  795. $this->expectException(InvalidFixerConfigurationException::class);
  796. $this->expectExceptionMessageMatches("#^\\[{$this->fixer->getName()}\\] {$expectedMessage}$#");
  797. $this->fixer->configure($config);
  798. }
  799. public static function provideInvalidConfigCases(): iterable
  800. {
  801. yield [['equal' => 2], 'Invalid configuration: The option "equal" with value 2 is expected to be of type "bool" or "null", but is of type "(int|integer)"\.'];
  802. yield [['_invalid_' => true], 'Invalid configuration: The option "_invalid_" does not exist\. Defined options are: "always_move_variable", "equal", "identical", "less_and_greater"\.'];
  803. }
  804. public function testDefinition(): void
  805. {
  806. self::assertInstanceOf(FixerDefinitionInterface::class, $this->fixer->getDefinition());
  807. }
  808. /**
  809. * @dataProvider providePHP71Cases
  810. */
  811. public function testPHP71(string $expected, ?string $input = null): void
  812. {
  813. $this->fixer->configure(['equal' => true, 'identical' => true]);
  814. $this->doTest($expected, $input);
  815. }
  816. /**
  817. * Test with the inverse config.
  818. *
  819. * @dataProvider providePHP71Cases
  820. */
  821. public function testPHP71Inverse(string $expected, ?string $input = null): void
  822. {
  823. $this->fixer->configure(['equal' => false, 'identical' => false]);
  824. if (null === $input) {
  825. $this->doTest($expected);
  826. } else {
  827. $this->doTest($input, $expected);
  828. }
  829. }
  830. public static function providePHP71Cases(): iterable
  831. {
  832. // no fix cases
  833. yield ['<?php list("a" => $a, "b" => $b, "c" => $c) = $c === array(1) ? $b : $d;'];
  834. yield ['<?php list(list("x" => $x1, "y" => $y1), list("x" => $x2, "y" => $y2)) = $points;'];
  835. yield ['<?php list("first" => list($x1, $y1), "second" => list($x2, $y2)) = $points;'];
  836. yield ['<?php [$a, $b, $c] = [1, 2, 3];'];
  837. yield ['<?php ["a" => $a, "b" => $b, "c" => $c] = $a[0];'];
  838. yield ['<?php list("a" => $a, "b" => $b, "c" => $c) = $c === array(1) ? $b : $d;'];
  839. yield ['<?php $b = 7 === [$a] = [7];']; // makes no sense, but valid PHP syntax
  840. yield ['<?php $b = 7 === [$a] = [7];'];
  841. yield ['<?php [$a] = $c === array(1) ? $b : $d;'];
  842. yield ['<?php $b = 7 === [$a] = [7];'];
  843. yield ['<?php $z = $n == [$a] = $b;'];
  844. yield ['<?php return $n == [$a] = $b;'];
  845. // fix cases
  846. yield [
  847. '<?php list("a" => $a, "b" => $b, "c" => $c) = 1 === $c ? $b : $d;',
  848. '<?php list("a" => $a, "b" => $b, "c" => $c) = $c === 1 ? $b : $d;',
  849. ];
  850. yield [
  851. '<?php list("a" => $a, "b" => $b, "c" => $c) = A::B === $c ? $b : $d;',
  852. '<?php list("a" => $a, "b" => $b, "c" => $c) = $c === A::B ? $b : $d;',
  853. ];
  854. yield [
  855. '<?php list( (2 === $c ? "a" : "b") => $b) = ["a" => 7 === $c ? 5 : 1, "b" => 7];',
  856. '<?php list( ($c === 2 ? "a" : "b") => $b) = ["a" => $c === 7 ? 5 : 1, "b" => 7];',
  857. ];
  858. yield [
  859. '<?php [ (ABC::A === $c ? "a" : "b") => $b] = ["a" => 7 === $c ? 5 : 1, "b" => 7];',
  860. '<?php [ ($c === ABC::A ? "a" : "b") => $b] = ["a" => $c === 7 ? 5 : 1, "b" => 7];',
  861. ];
  862. yield 'Array destruct by ternary.' => [
  863. '<?php [$a] = 11 === $c ? $b : $d;',
  864. '<?php [$a] = $c === 11 ? $b : $d;',
  865. ];
  866. yield [
  867. '<?php $b = [$a] = 7 === [7];', // makes no sense, but valid PHP syntax
  868. '<?php $b = [$a] = [7] === 7;',
  869. ];
  870. }
  871. /**
  872. * @param _AutogeneratedInputConfiguration $config
  873. *
  874. * @dataProvider provideWithConfigCases
  875. */
  876. public function testWithConfig(array $config, string $expected): void
  877. {
  878. $this->fixer->configure($config);
  879. $this->doTest($expected);
  880. }
  881. public static function provideWithConfigCases(): iterable
  882. {
  883. yield [
  884. [
  885. 'identical' => false,
  886. ],
  887. '<?php
  888. $a = [1, 2, 3];
  889. while (2 !== $b = array_pop($c));
  890. ',
  891. ];
  892. yield [
  893. [
  894. 'equal' => false,
  895. 'identical' => false,
  896. ],
  897. '<?php
  898. if ($revision->event == \'created\') {
  899. foreach ($revision->getModified() as $col => $data) {
  900. $model->$col = $data[\'new\'];
  901. }
  902. } else {
  903. foreach ($revision->getModified() as $col => $data) {
  904. $model->$col = $data[\'old\'];
  905. }
  906. }',
  907. ];
  908. }
  909. /**
  910. * @dataProvider provideFixPrePHP80Cases
  911. *
  912. * @requires PHP <8.0
  913. */
  914. public function testFixPrePHP80(string $expected, ?string $input = null): void
  915. {
  916. $this->doTest($expected, $input);
  917. }
  918. public static function provideFixPrePHP80Cases(): iterable
  919. {
  920. yield [
  921. '<?php return \A/*5*/\/*6*/B\/*7*/C::MY_CONST === \A/*1*//*1*//*1*//*1*//*1*/\/*2*/B/*3*/\C/*4*/::$myVariable;',
  922. '<?php return \A/*1*//*1*//*1*//*1*//*1*/\/*2*/B/*3*/\C/*4*/::$myVariable === \A/*5*/\/*6*/B\/*7*/C::MY_CONST;',
  923. ];
  924. yield [
  925. '<?php return A\/**//**//**/B/*a*//*a*//*a*//*a*/::MY_CONST === B\C::$myVariable;',
  926. '<?php return B\C::$myVariable === A\/**//**//**/B/*a*//*a*//*a*//*a*/::MY_CONST;',
  927. ];
  928. yield ['<?php return $foo === $bar[$baz]{1};'];
  929. yield ['<?php return $foo->$a[1] === $bar[$baz]{1}->$a[1][2][3]->$d[$z]{1};'];
  930. yield ['<?php return $m->a{2}+1 == 2;'];
  931. yield ['<?php return $m{2}+1 == 2;'];
  932. yield [
  933. '<?php echo 1 === (unset) $a ? 8 : 7;',
  934. '<?php echo (unset) $a === 1 ? 8 : 7;',
  935. ];
  936. }
  937. /**
  938. * @param _AutogeneratedInputConfiguration $config
  939. *
  940. * @dataProvider provideFix80Cases
  941. *
  942. * @requires PHP 8.0
  943. */
  944. public function testFix80(string $expected, ?string $input = null, array $config = []): void
  945. {
  946. $this->fixer->configure($config);
  947. $this->doTest($expected, $input);
  948. }
  949. public static function provideFix80Cases(): iterable
  950. {
  951. yield [
  952. '<?php
  953. if ($a = true === $obj instanceof (foo())) {
  954. echo 1;
  955. }',
  956. '<?php
  957. if ($a = $obj instanceof (foo()) === true) {
  958. echo 1;
  959. }',
  960. ];
  961. yield [
  962. '<?php $i = $this?->getStuff() === $myVariable;',
  963. '<?php $i = $myVariable === $this?->getStuff();',
  964. ['equal' => true, 'identical' => true, 'always_move_variable' => true],
  965. ];
  966. yield [
  967. '<?php 42 === $a->b[5]?->c;',
  968. '<?php $a->b[5]?->c === 42;',
  969. ];
  970. yield [
  971. '<?php return $this->myObject1?->{$index}+$b === "";',
  972. null,
  973. ['equal' => true, 'identical' => true],
  974. ];
  975. yield [
  976. '<?php new Foo(bar: 1 === $var);',
  977. '<?php new Foo(bar: $var === 1);',
  978. ];
  979. }
  980. /**
  981. * @dataProvider provideFix81Cases
  982. *
  983. * @requires PHP 8.1
  984. */
  985. public function testFix81(string $expected, ?string $input = null): void
  986. {
  987. $this->doTest($expected, $input);
  988. }
  989. public static function provideFix81Cases(): iterable
  990. {
  991. yield 'does not make a lot of sense but is valid syntax, do not break 1' => [
  992. '<?php $b = strlen( ... ) === $a;',
  993. ];
  994. yield 'does not make a lot of sense but is valid syntax, do not break 2' => [
  995. '<?php $b = $a === strlen( ... );',
  996. ];
  997. }
  998. }