YodaStyleFixerTest.php 32 KB

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