OperatorLinebreakFixerTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  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\Operator;
  13. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  14. /**
  15. * @author Kuba Werłos <werlos@gmail.com>
  16. *
  17. * @covers \PhpCsFixer\Fixer\Operator\OperatorLinebreakFixer
  18. *
  19. * @internal
  20. *
  21. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\Operator\OperatorLinebreakFixer>
  22. *
  23. * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\Operator\OperatorLinebreakFixer
  24. */
  25. final class OperatorLinebreakFixerTest extends AbstractFixerTestCase
  26. {
  27. /**
  28. * @param _AutogeneratedInputConfiguration $configuration
  29. *
  30. * @dataProvider provideFixCases
  31. */
  32. public function testFix(string $expected, ?string $input = null, array $configuration = []): void
  33. {
  34. $this->fixer->configure($configuration);
  35. $this->doTest($expected, $input);
  36. }
  37. public static function provideFixCases(): iterable
  38. {
  39. foreach (self::pairs() as $key => $value) {
  40. yield \sprintf('%s when position is "beginning"', $key) => $value;
  41. yield \sprintf('%s when position is "end"', $key) => [
  42. $value[1],
  43. $value[0],
  44. ['position' => 'end'],
  45. ];
  46. }
  47. yield 'ignore add operator when only booleans enabled' => [
  48. '<?php
  49. return $foo
  50. +
  51. $bar;
  52. ',
  53. null,
  54. ['only_booleans' => true],
  55. ];
  56. yield 'handle operator when on separate line when position is "beginning"' => [
  57. '<?php
  58. return $foo
  59. || $bar;
  60. ',
  61. '<?php
  62. return $foo
  63. ||
  64. $bar;
  65. ',
  66. ];
  67. yield 'handle operator when on separate line when position is "end"' => [
  68. '<?php
  69. return $foo ||
  70. $bar;
  71. ',
  72. '<?php
  73. return $foo
  74. ||
  75. $bar;
  76. ',
  77. ['position' => 'end'],
  78. ];
  79. yield 'handle Elvis operator with space inside' => [
  80. '<?php
  81. return $foo
  82. ?: $bar;
  83. ',
  84. '<?php
  85. return $foo ? :
  86. $bar;
  87. ',
  88. ];
  89. yield 'handle Elvis operator with space inside when position is "end"' => [
  90. '<?php
  91. return $foo ?:
  92. $bar;
  93. ',
  94. '<?php
  95. return $foo
  96. ? : $bar;
  97. ',
  98. ['position' => 'end'],
  99. ];
  100. yield 'handle Elvis operator with comment inside' => [
  101. '<?php
  102. return $foo/* Lorem ipsum */
  103. ?: $bar;
  104. ',
  105. '<?php
  106. return $foo ?/* Lorem ipsum */:
  107. $bar;
  108. ',
  109. ];
  110. yield 'handle Elvis operators with comment inside when position is "end"' => [
  111. '<?php
  112. return $foo ?:
  113. /* Lorem ipsum */$bar;
  114. ',
  115. '<?php
  116. return $foo
  117. ?/* Lorem ipsum */: $bar;
  118. ',
  119. ['position' => 'end'],
  120. ];
  121. yield 'assign by reference' => [
  122. '<?php
  123. $a
  124. = $b;
  125. $c =&
  126. $d;
  127. ',
  128. '<?php
  129. $a =
  130. $b;
  131. $c =&
  132. $d;
  133. ',
  134. ];
  135. yield 'passing by reference' => [
  136. '<?php
  137. function foo(
  138. &$a,
  139. &$b,
  140. int
  141. &$c,
  142. \Bar\Baz
  143. &$d
  144. ) {};',
  145. null,
  146. ['position' => 'end'],
  147. ];
  148. yield 'multiple switches' => [
  149. '<?php
  150. switch ($foo) {
  151. case 1:
  152. break;
  153. case 2:
  154. break;
  155. }
  156. switch($bar) {
  157. case 1:
  158. break;
  159. case 2:
  160. break;
  161. }',
  162. ];
  163. yield 'return type' => [
  164. '<?php
  165. function foo()
  166. :
  167. bool
  168. {};',
  169. ];
  170. yield 'go to' => ['<?php
  171. prepare_value:
  172. $objectsPool[$value] = [$id = \count($objectsPool)];
  173. '];
  174. yield 'alternative syntax' => [
  175. '<?php
  176. if (true):
  177. echo 1;
  178. else:
  179. echo 2;
  180. endif;
  181. while (true):
  182. echo "na";
  183. endwhile;
  184. ',
  185. null,
  186. ['position' => 'beginning'],
  187. ];
  188. yield 'nullable type when position is "end"' => [
  189. '<?php
  190. function foo(
  191. ?int $x,
  192. ?int $y,
  193. ?int $z
  194. ) {};',
  195. null,
  196. ['position' => 'end'],
  197. ];
  198. }
  199. /**
  200. * @dataProvider provideFix80Cases
  201. *
  202. * @requires PHP 8.0
  203. */
  204. public function testFix80(string $expected, ?string $input = null): void
  205. {
  206. $this->doTest($expected, $input);
  207. }
  208. /**
  209. * @return iterable<array{string, 1?: string}>
  210. */
  211. public static function provideFix80Cases(): iterable
  212. {
  213. yield 'handle ?-> operator' => [
  214. '<?php
  215. $foo
  216. ?-> $bar;
  217. ',
  218. '<?php
  219. $foo ?->
  220. $bar;
  221. ',
  222. ];
  223. }
  224. /**
  225. * @return iterable<array{0: string, 1: null|string, 2?: array<string, mixed>}>
  226. */
  227. private static function pairs(): iterable
  228. {
  229. yield 'handle equal sign' => [
  230. '<?php
  231. $foo
  232. = $bar;
  233. ',
  234. '<?php
  235. $foo =
  236. $bar;
  237. ',
  238. ];
  239. yield 'handle add operator' => [
  240. '<?php
  241. return $foo
  242. + $bar;
  243. ',
  244. '<?php
  245. return $foo +
  246. $bar;
  247. ',
  248. ['only_booleans' => false],
  249. ];
  250. yield 'handle uppercase operator' => [
  251. '<?php
  252. return $foo
  253. AND $bar;
  254. ',
  255. '<?php
  256. return $foo AND
  257. $bar;
  258. ',
  259. ];
  260. yield 'handle concatenation operator' => [
  261. '<?php
  262. return $foo
  263. .$bar;
  264. ',
  265. '<?php
  266. return $foo.
  267. $bar;
  268. ',
  269. ];
  270. yield 'handle ternary operator' => [
  271. '<?php
  272. return $foo
  273. ? $bar
  274. : $baz;
  275. ',
  276. '<?php
  277. return $foo ?
  278. $bar :
  279. $baz;
  280. ',
  281. ];
  282. yield 'handle multiple operators' => [
  283. '<?php
  284. return $foo
  285. || $bar
  286. || $baz;
  287. ',
  288. '<?php
  289. return $foo ||
  290. $bar ||
  291. $baz;
  292. ',
  293. ];
  294. yield 'handle multiple operators with nested' => [
  295. '<?php
  296. return $foo
  297. || $bar
  298. || ($bar2 || $bar3)
  299. || $baz;
  300. ',
  301. '<?php
  302. return $foo ||
  303. $bar ||
  304. ($bar2 || $bar3) ||
  305. $baz;
  306. ',
  307. ];
  308. yield 'handle operator when no whitespace is before' => [
  309. '<?php
  310. function foo() {
  311. return $a
  312. ||$b;
  313. }
  314. ',
  315. '<?php
  316. function foo() {
  317. return $a||
  318. $b;
  319. }
  320. ',
  321. ];
  322. yield 'handle operator with one-line comments' => [
  323. '<?php
  324. function getNewCuyamaTotal() {
  325. return 562 // Population
  326. + 2150 // Ft. above sea level
  327. + 1951; // Established
  328. }
  329. ',
  330. '<?php
  331. function getNewCuyamaTotal() {
  332. return 562 + // Population
  333. 2150 + // Ft. above sea level
  334. 1951; // Established
  335. }
  336. ',
  337. ];
  338. yield 'handle operator with PHPDoc comments' => [
  339. '<?php
  340. function getNewCuyamaTotal() {
  341. return 562 /** Population */
  342. + 2150 /** Ft. above sea level */
  343. + 1951; /** Established */
  344. }
  345. ',
  346. '<?php
  347. function getNewCuyamaTotal() {
  348. return 562 + /** Population */
  349. 2150 + /** Ft. above sea level */
  350. 1951; /** Established */
  351. }
  352. ',
  353. ];
  354. yield 'handle operator with multiple comments next to each other' => [
  355. '<?php
  356. function foo() {
  357. return isThisTheRealLife() // First comment
  358. // Second comment
  359. // Third comment
  360. || isThisJustFantasy();
  361. }
  362. ',
  363. '<?php
  364. function foo() {
  365. return isThisTheRealLife() || // First comment
  366. // Second comment
  367. // Third comment
  368. isThisJustFantasy();
  369. }
  370. ',
  371. ];
  372. yield 'handle nested operators' => [
  373. '<?php
  374. function foo() {
  375. return $a
  376. && (
  377. $b
  378. || $c
  379. )
  380. && $d;
  381. }
  382. ',
  383. '<?php
  384. function foo() {
  385. return $a &&
  386. (
  387. $b ||
  388. $c
  389. ) &&
  390. $d;
  391. }
  392. ',
  393. ];
  394. yield 'handle Elvis operator' => [
  395. '<?php
  396. return $foo
  397. ?: $bar;
  398. ',
  399. '<?php
  400. return $foo ?:
  401. $bar;
  402. ',
  403. ];
  404. yield 'handle ternary operator inside of switch' => [
  405. '<?php
  406. switch ($foo) {
  407. case 1:
  408. return $isOK ? 1 : -1;
  409. case (
  410. $a
  411. ? 2
  412. : 3
  413. ) :
  414. return 23;
  415. case $b[
  416. $a
  417. ? 4
  418. : 5
  419. ]
  420. : return 45;
  421. }
  422. ',
  423. '<?php
  424. switch ($foo) {
  425. case 1:
  426. return $isOK ? 1 : -1;
  427. case (
  428. $a ?
  429. 2 :
  430. 3
  431. ) :
  432. return 23;
  433. case $b[
  434. $a ?
  435. 4 :
  436. 5
  437. ]
  438. : return 45;
  439. }
  440. ',
  441. ];
  442. yield 'handle ternary operator with switch inside' => [
  443. '<?php
  444. $a
  445. ? array_map(
  446. function () {
  447. switch (true) {
  448. case 1:
  449. return true;
  450. }
  451. },
  452. [1, 2, 3]
  453. )
  454. : false;
  455. ',
  456. '<?php
  457. $a ?
  458. array_map(
  459. function () {
  460. switch (true) {
  461. case 1:
  462. return true;
  463. }
  464. },
  465. [1, 2, 3]
  466. ) :
  467. false;
  468. ',
  469. ];
  470. $operators = [
  471. '+', '-', '*', '/', '%', '**', // Arithmetic
  472. '+=', '-=', '*=', '/=', '%=', '**=', // Arithmetic assignment
  473. '=', // Assignment
  474. '&', '|', '^', '<<', '>>', // Bitwise
  475. '&=', '|=', '^=', '<<=', '>>=', // Bitwise assignment
  476. '==', '===', '!=', '<>', '!==', '<', '>', '<=', '>=', // Comparison
  477. 'and', 'or', 'xor', '&&', '||', // Logical
  478. '.', '.=', // String
  479. '->', // Object
  480. '::', // Scope Resolution
  481. ];
  482. $operators[] = '??';
  483. $operators[] = '<=>';
  484. foreach ($operators as $operator) {
  485. yield \sprintf('handle %s operator', $operator) => [
  486. \sprintf('<?php
  487. $foo
  488. %s $bar;
  489. ', $operator),
  490. \sprintf('<?php
  491. $foo %s
  492. $bar;
  493. ', $operator),
  494. ];
  495. }
  496. yield 'handle => operator' => [
  497. '<?php
  498. [$foo
  499. => $bar];
  500. ',
  501. '<?php
  502. [$foo =>
  503. $bar];
  504. ',
  505. ];
  506. yield 'handle & operator with constant' => [
  507. '<?php
  508. \Foo::bar
  509. & $baz;
  510. ',
  511. '<?php
  512. \Foo::bar &
  513. $baz;
  514. ',
  515. ];
  516. }
  517. }