YodaStyleFixerTest.php 33 KB

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