OperatorLinebreakFixerTest.php 10 KB

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