AssignNullCoalescingToCoalesceEqualFixerTest.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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. * @internal
  16. *
  17. * @covers \PhpCsFixer\Fixer\AbstractShortOperatorFixer
  18. * @covers \PhpCsFixer\Fixer\Operator\AssignNullCoalescingToCoalesceEqualFixer
  19. *
  20. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\Operator\AssignNullCoalescingToCoalesceEqualFixer>
  21. */
  22. final class AssignNullCoalescingToCoalesceEqualFixerTest extends AbstractFixerTestCase
  23. {
  24. /**
  25. * @dataProvider provideFixCases
  26. */
  27. public function testFix(string $expected, ?string $input = null): void
  28. {
  29. $this->doTest($expected, $input);
  30. }
  31. /**
  32. * @return iterable<int|string, array{0: string, 1?: string}>
  33. */
  34. public static function provideFixCases(): iterable
  35. {
  36. yield 'simple' => [
  37. '<?php $a ??= 1;',
  38. '<?php $a = $a ?? 1;',
  39. ];
  40. yield 'minimal' => [
  41. '<?php $a ??= 1;',
  42. '<?php $a=$a??1;',
  43. ];
  44. yield 'simple array' => [
  45. '<?php $a[1] ??= 1;',
  46. '<?php $a[1] = $a[1] ?? 1;',
  47. ];
  48. yield 'simple array [0]' => [
  49. '<?php $a[1][0] ??= 1;',
  50. '<?php $a[1][0] = $a[1][0] ?? 1;',
  51. ];
  52. yield 'simple array ([0])' => [
  53. '<?php $a[1][0] ??= 1;',
  54. '<?php $a[1][0] = ($a[1][0]) ?? 1;',
  55. ];
  56. yield 'simple array, comment' => [
  57. '<?php $a[1] /* 1 */ ??= /* 2 */ /* 3 */ /* 4 */ /* 5 */ 1;',
  58. '<?php $a[1]/* 1 */ = /* 2 */ $a[1/* 3 */] /* 4 */ ??/* 5 */ 1;',
  59. ];
  60. yield 'simple in call' => [
  61. '<?php a(1, $a ??= 1);',
  62. '<?php a(1, $a = $a ?? 1);',
  63. ];
  64. yield [
  65. '<?php \A\B::$foo ??= 1;',
  66. '<?php \A\B::$foo = \A\B::$foo ?? 1;',
  67. ];
  68. yield 'same' => [
  69. '<?php $a ??= 1;',
  70. '<?php $a = ($a) ?? 1;',
  71. ];
  72. yield 'object' => [
  73. '<?php $a->b ??= 1;',
  74. '<?php $a->b = $a->b ?? 1;',
  75. ];
  76. yield 'object II' => [
  77. '<?php $a->b[0]->{1} ??= 1;',
  78. '<?php $a->b[0]->{1} = $a->b[0]->{1} ?? 1;',
  79. ];
  80. yield 'simple, before ;' => [
  81. '<?php ; $a ??= 1;',
  82. '<?php ; $a = $a ?? 1;',
  83. ];
  84. yield 'simple, before {' => [
  85. '<?php { $a ??= 1; }',
  86. '<?php { $a = $a ?? 1; }',
  87. ];
  88. yield 'simple, before }' => [
  89. '<?php if ($a){} $a ??= 1;',
  90. '<?php if ($a){} $a = $a ?? 1;',
  91. ];
  92. yield 'in call' => [
  93. '<?php foo($a ??= 1);',
  94. '<?php foo($a = $a ?? 1);',
  95. ];
  96. yield 'in call followed by end tag and ternary' => [
  97. '<?php foo( $a ??= 1 ) ?><?php $b = $b ? $c : $d ?>',
  98. '<?php foo( $a = $a ?? 1 ) ?><?php $b = $b ? $c : $d ?>',
  99. ];
  100. yield 'simple, before ) I' => [
  101. '<?php if ($a) $a ??= 1;',
  102. '<?php if ($a) $a = $a ?? 1;',
  103. ];
  104. yield 'simple, before ) II' => [
  105. '<?php
  106. if ($a) $a ??= 1;
  107. foreach ($d as $i) $a ??= 1;
  108. while (foo()) $a ??= 1;
  109. ',
  110. '<?php
  111. if ($a) $a = $a ?? 1;
  112. foreach ($d as $i) $a = $a ?? 1;
  113. while (foo()) $a = $a ?? 1;
  114. ',
  115. ];
  116. yield 'simple, end' => [
  117. '<?php $a ??= 1 ?>',
  118. '<?php $a = $a ?? 1 ?>',
  119. ];
  120. yield 'simple, 10x' => [
  121. '<?php'.str_repeat(' $a ??= 1;', 10),
  122. '<?php'.str_repeat(' $a = $a ?? 1;', 10),
  123. ];
  124. yield 'simple, multi line' => [
  125. '<?php
  126. $a
  127. ??=
  128. '.'
  129. '.'
  130. 1;',
  131. '<?php
  132. $a
  133. =
  134. $a
  135. ??
  136. 1;',
  137. ];
  138. yield 'dynamic var' => [
  139. '<?php ${beers::$ale} ??= 1;',
  140. '<?php ${beers::$ale} = ${beers::$ale} ?? 1;',
  141. ];
  142. yield [
  143. '<?php $argv ??= $_SERVER[\'argv\'] ?? [];',
  144. '<?php $argv = $argv ?? $_SERVER[\'argv\'] ?? [];',
  145. ];
  146. yield 'do not fix' => [
  147. '<?php
  148. $a = 1 + $a ?? $b;
  149. $b + $a = $a ?? 1;
  150. $b = $a ?? 1;
  151. $b = $a ?? $b;
  152. $d = $a + $c ; $c ?? $c;
  153. $a = ($a ?? $b) && $c; // just to be sure
  154. $a = (string) $a ?? 1;
  155. $a = 1 ?? $a;
  156. ',
  157. ];
  158. yield 'do not fix because of precedence 1' => [
  159. '<?php $a = $a ?? $b ? $c : $d;',
  160. ];
  161. yield 'do not fix because of precedence 2' => [
  162. '<?php $a = $a ?? $b ? $c : $d ?>',
  163. ];
  164. yield ['<?php $a[1][0] = $a ?? $a[1][0];'];
  165. yield 'switch case & default' => [
  166. '<?php
  167. switch(foo()) {
  168. case 1:
  169. $a ??= 1;
  170. break;
  171. default:
  172. $b ??= 1;
  173. break;
  174. }
  175. ',
  176. '<?php
  177. switch(foo()) {
  178. case 1:
  179. $a = $a ?? 1;
  180. break;
  181. default:
  182. $b = $b ?? 1;
  183. break;
  184. }
  185. ',
  186. ];
  187. yield 'operator precedence' => [
  188. '<?php $x = $z ? $b : $a = $a ?? 123;',
  189. ];
  190. yield 'alternative syntax' => [
  191. '<?php foreach([1, 2, 3] as $i): $a ??= 1; endforeach;',
  192. '<?php foreach([1, 2, 3] as $i): $a = $a ?? 1; endforeach;',
  193. ];
  194. yield 'assign and return' => [
  195. '<?php
  196. class Foo
  197. {
  198. private $test;
  199. public function bar($i)
  200. {
  201. return $this->test ??= $i;
  202. }
  203. }',
  204. '<?php
  205. class Foo
  206. {
  207. private $test;
  208. public function bar($i)
  209. {
  210. return $this->test = $this->test ?? $i;
  211. }
  212. }',
  213. ];
  214. }
  215. /**
  216. * @dataProvider provideFixPre80Cases
  217. *
  218. * @requires PHP <8.0
  219. */
  220. public function testFixPre80(string $expected, ?string $input = null): void
  221. {
  222. $this->doTest($expected, $input);
  223. }
  224. /**
  225. * @return iterable<string, array{string, 1?: string}>
  226. */
  227. public static function provideFixPre80Cases(): iterable
  228. {
  229. yield 'mixed array' => [
  230. '<?php
  231. $a[1] ??= 1;
  232. $a{2} ??= 1;
  233. $a{2}[$f] ??= 1;
  234. ',
  235. '<?php
  236. $a[1] = $a[1] ?? 1;
  237. $a{2} = $a{2} ?? 1;
  238. $a{2}[$f] = $a{2}[$f] ?? 1;
  239. ',
  240. ];
  241. yield 'same II' => [
  242. '<?php $a[1] ??= 1;',
  243. '<?php $a[1] = $a{1} ?? 1;',
  244. ];
  245. yield 'same III' => [
  246. '<?php $a[1] ??= 1;',
  247. '<?php $a[1] = (($a{1})) ?? 1;',
  248. ];
  249. }
  250. }