NoUselessConcatOperatorFixerTest.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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\Operator\NoUselessConcatOperatorFixer
  18. *
  19. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\Operator\NoUselessConcatOperatorFixer>
  20. *
  21. * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\Operator\NoUselessConcatOperatorFixer
  22. */
  23. final class NoUselessConcatOperatorFixerTest extends AbstractFixerTestCase
  24. {
  25. /**
  26. * @dataProvider provideFixCases
  27. */
  28. public function testFix(string $expected, ?string $input = null): void
  29. {
  30. $this->fixer->configure(['juggle_simple_strings' => true]);
  31. $this->doTest($expected, $input);
  32. }
  33. /**
  34. * @return iterable<int|string, array{0: string, 1?: string}>
  35. */
  36. public static function provideFixCases(): iterable
  37. {
  38. $templateExpected = '<?php $b = %s;';
  39. $templateInput = '<?php $b = %s.%s;';
  40. $cases = [
  41. 'single . single' => ["'a'", "'b'", "'ab'"],
  42. 'single . double' => ["'a'", '"b"', '"ab"'],
  43. 'double . single' => ['"b\n"', "'a'", '"b\na"'],
  44. 'double . double' => ['"b"', '"b"', '"bb"'],
  45. 'encapsed . encapsed' => ['"{$a}"', '"{$b}"', '"{$a}{$b}"'],
  46. 'encapsed space. encapsed' => ['"{$a1} "', '"{$b2}"', '"{$a1} {$b2}"'],
  47. 'encapsed . space encapsed' => ['"{$a}"', '" {$b}"', '"{$a} {$b}"'],
  48. 'encapsed space. space encapsed' => ['"{$a} "', '" {$b}"', '"{$a} {$b}"'],
  49. 'encapsed . single' => ['"{$a}"', "'Z'", '"{$a}Z"'],
  50. 'single . encapsed' => ["'Y'", '"{$a}"', '"Y{$a}"'],
  51. 'encapsed spaced. single' => ['"{$a} "', "'G'", '"{$a} G"'],
  52. 'single . space encapsed' => ["'V'", '" {$a}"', '"V {$a}"'],
  53. 'encapsed . double' => ['"{$a} "', '"XX"', '"{$a} XX"'],
  54. 'double . encapsed' => ['"XCV"', '"{$a}"', '"XCV{$a}"'],
  55. 'encapsed spaced . double' => ['"{$a} V "', '"PO"', '"{$a} V PO"'],
  56. 'double . space encapsed' => ['"DSA"', '" XX {$a}"', '"DSA XX {$a}"'],
  57. ];
  58. foreach ($cases as $label => $case) {
  59. yield $label => [
  60. \sprintf($templateExpected, $case[2]),
  61. \sprintf($templateInput, $case[0], $case[1]),
  62. ];
  63. }
  64. yield 'encapsed followed by simple double quoted 1' => [
  65. '<?php echo "Hello, {$fruit}s.";',
  66. '<?php echo \'Hello,\' . " {$fruit}s.";',
  67. ];
  68. yield 'encapsed followed by simple double quoted 2' => [
  69. '<?php echo "Hello.He drank some juice made of {$fruit}s.Bye $user!" /*1*//*2*/ /*3*//*4*/;',
  70. '<?php echo \'Hello.\' /*1*/ . /*2*/ "He drank some juice made of {$fruit}s."/*3*/./*4*/"Bye $user!";',
  71. ];
  72. yield [
  73. '<?php
  74. $string = "foobar";
  75. echo "char @ -4 \"[$string[-2]]\"!";
  76. ',
  77. '<?php
  78. $string = "foobar";
  79. echo "char @ -4 \"[$string[-2]"."]\"!";
  80. ',
  81. ];
  82. yield 'double quote concat double quote + comment' => [
  83. '<?php $fi = "lk" /* 1 *//* 2 */ ;',
  84. '<?php $fi = "l" /* 1 */ . /* 2 */ "k";',
  85. ];
  86. yield 'empty concat empty' => [
  87. '<?php $aT = "";',
  88. '<?php $aT = ""."";',
  89. ];
  90. yield 'multiple fixes' => [
  91. '<?php $f0 = "abc | defg";',
  92. '<?php $f0 = "a"."b"."c | "."d"."e"."f"."g";',
  93. ];
  94. yield 'linebreak with indent inside' => [
  95. '<?php
  96. $text1 = "intro: | |"."
  97. line 2 indent";',
  98. '<?php
  99. $text1 = "intro: |"." |"."
  100. line 2 indent"."";',
  101. ];
  102. yield 'linebreak with indent inside + comment' => [
  103. '<?php
  104. $text2 = "intro: "." #a
  105. line 2 indent";',
  106. '<?php
  107. $text2 = "intro: "." "." #a
  108. line 2 indent"."";',
  109. ];
  110. yield 'do not fix' => [
  111. '<?php
  112. $a0x = $b . "c";
  113. $a1x = "c" . $b;
  114. $b2x = foo() . "X";
  115. $b3x = foo() . \'Y\';
  116. $b4x = "Z" . foo();
  117. $b5x = \'b\' . foo();
  118. $b6x = \'X \n \' . "\n\t";
  119. $b7x = "\n\t" . \'X $a\';
  120. $b7x = "abc". 1;
  121. $b7x = "def". 1.2;
  122. // bin string
  123. $f202 = b"a"."b";
  124. $f201 = b"a".b"b";
  125. $f203 = "a".B"b";
  126. echo b"He drank some juice made of {$fruit}s.".b" Sliced the {$fruit}s.";
  127. ',
  128. ];
  129. yield 'do not fix if the execution result would be different' => [
  130. '<?php
  131. echo "abc $d" . "[$e]";
  132. echo "abc $d" . "[3]";
  133. echo "abc $d" . \'[3]\';
  134. echo "abc $d" . "->e";
  135. echo "abc $d" . \'->e\';
  136. echo "abc $d" . "->$e";
  137. echo "abc $d" . "?->e";
  138. echo "abc $d" . "?->$e";
  139. echo "abc $d" . \'?->e\';
  140. ',
  141. ];
  142. yield 'do not fix if variables would be broken' => [
  143. '<?php
  144. echo "abc $d" . "e $f";
  145. echo "abc $d" . "e";
  146. echo "abc $d" . " e"; // contains full-width space
  147. echo "abc $d" . \'e\';
  148. echo "abc $d" . \' e\'; // contains full-width space
  149. echo "abc $d" . "😃"; // with emoji
  150. echo "私の名前は$name" . "です"; // multibyte characters (Japanese)
  151. ',
  152. ];
  153. yield 'fix if variables would not be broken' => [
  154. '<?php
  155. echo "$a b";
  156. echo "$a bcde";
  157. echo "abc ${d}e";
  158. echo "abc $d-efg";
  159. echo "$a bcdef";
  160. echo "abc ${d}ef";
  161. echo "abc $d-efgh";
  162. echo "abc $d-$e";
  163. ',
  164. '<?php
  165. echo "$a" . " b";
  166. echo "$a bc" . "de";
  167. echo "abc ${d}" . "e";
  168. echo "abc $d" . "-efg";
  169. echo "$a bc" . \'def\';
  170. echo "abc ${d}" . \'ef\';
  171. echo "abc $d" . \'-efgh\';
  172. echo "abc $d" . "-$e";
  173. ',
  174. ];
  175. yield 'single quote concat single quote but with line break after' => [
  176. "<?php \$fh = 'x'. // some comment
  177. 'y';",
  178. ];
  179. yield 'single quote concat single quote but with line break before' => [
  180. "<?php \$ff = 'x' // some comment
  181. .'y';",
  182. ];
  183. yield 'linebreak without indent inside' => [
  184. '<?php
  185. $text3 = "intro:"."
  186. line 2 indent" ?>',
  187. ];
  188. yield 'linebreak before concat + comment' => [
  189. "<?php
  190. \$a = 'The first line of some block.'
  191. .'The second line' // some comment about this line
  192. .'3rd line'
  193. ;
  194. ",
  195. ];
  196. yield 'concat without linebreak, followed by one with linebreak' => [
  197. <<<'PHP'
  198. <?php
  199. $foo = 'ab'
  200. . 'c';
  201. PHP,
  202. <<<'PHP'
  203. <?php
  204. $foo = 'a' . 'b'
  205. . 'c';
  206. PHP,
  207. ];
  208. }
  209. public function testWithConfigJuggling(): void
  210. {
  211. $input = '<?php $a = "x" . \'y\';';
  212. $expected = '<?php $a = "xy";';
  213. $this->fixer->configure(['juggle_simple_strings' => true]);
  214. $this->doTest($expected, $input);
  215. $this->fixer->configure(['juggle_simple_strings' => false]);
  216. $this->doTest($input);
  217. }
  218. }