NoUselessConcatOperatorFixerTest.php 7.3 KB

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