NoMixedEchoPrintFixerTest.php 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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\Alias;
  13. use PhpCsFixer\AbstractFixer;
  14. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  15. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  16. /**
  17. * @author Sullivan Senechal <soullivaneuh@gmail.com>
  18. *
  19. * @internal
  20. *
  21. * @covers \PhpCsFixer\Fixer\Alias\NoMixedEchoPrintFixer
  22. */
  23. final class NoMixedEchoPrintFixerTest extends AbstractFixerTestCase
  24. {
  25. /**
  26. * @dataProvider provideFixEchoToPrintCases
  27. */
  28. public function testFixEchoToPrint(string $expected, ?string $input = null): void
  29. {
  30. $this->fixer->configure(['use' => 'print']);
  31. $this->doTest($expected, $input);
  32. }
  33. public static function provideFixEchoToPrintCases(): iterable
  34. {
  35. yield [
  36. '<?php
  37. print "test";
  38. ',
  39. ];
  40. yield [
  41. '<?php
  42. print ("test");
  43. ',
  44. ];
  45. yield [
  46. '<?php
  47. print("test");
  48. ',
  49. ];
  50. // `echo` can take multiple parameters (although such usage is rare) while `print` can take only one argument,
  51. // @see https://php.net/manual/en/function.echo.php and @see https://php.net/manual/en/function.print.php
  52. yield [
  53. '<?php
  54. echo "This ", "string ", "was ", "made ", "with multiple parameters.";
  55. ',
  56. ];
  57. yield [
  58. '<?php
  59. print "test";
  60. ',
  61. '<?php
  62. echo "test";
  63. ',
  64. ];
  65. yield [
  66. '<?php
  67. print ("test");
  68. ',
  69. '<?php
  70. echo ("test");
  71. ',
  72. ];
  73. yield [
  74. '<?php
  75. print("test");
  76. ',
  77. '<?php
  78. echo("test");
  79. ',
  80. ];
  81. yield [
  82. '<?php
  83. print foo(1, 2);
  84. ',
  85. '<?php
  86. echo foo(1, 2);
  87. ',
  88. ];
  89. yield [
  90. '<?php
  91. print ["foo", "bar", "baz"][$x];
  92. ',
  93. '<?php
  94. echo ["foo", "bar", "baz"][$x];
  95. ',
  96. ];
  97. yield [
  98. '<?php
  99. print $foo ? "foo" : "bar";
  100. ',
  101. '<?php
  102. echo $foo ? "foo" : "bar";
  103. ',
  104. ];
  105. yield [
  106. "<?php print 'foo' ?>...<?php echo 'bar', 'baz' ?>",
  107. "<?php echo 'foo' ?>...<?php echo 'bar', 'baz' ?>",
  108. ];
  109. yield [
  110. '<?php
  111. if ($foo) {
  112. print "foo";
  113. }
  114. print "bar";
  115. ',
  116. '<?php
  117. if ($foo) {
  118. echo "foo";
  119. }
  120. echo "bar";
  121. ',
  122. ];
  123. yield [
  124. '<?=$foo?>',
  125. ];
  126. foreach (self::getCodeSnippetsToConvertBothWays() as $codeSnippet) {
  127. yield [
  128. sprintf($codeSnippet, 'print'),
  129. sprintf($codeSnippet, 'echo'),
  130. ];
  131. }
  132. }
  133. /**
  134. * @dataProvider provideFixPrintToEchoCases
  135. */
  136. public function testFixPrintToEcho(string $expected, ?string $input = null): void
  137. {
  138. $this->fixer->configure(['use' => 'echo']);
  139. $this->doTest($expected, $input);
  140. }
  141. public static function provideFixPrintToEchoCases(): iterable
  142. {
  143. yield [
  144. '<?php
  145. echo "test";
  146. ',
  147. ];
  148. yield [
  149. '<?php
  150. echo ("test");
  151. ',
  152. ];
  153. yield [
  154. '<?php
  155. echo("test");
  156. ',
  157. ];
  158. // https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/1502#issuecomment-156436229
  159. yield [
  160. '<?php
  161. ($some_var) ? print "true" : print "false";
  162. ',
  163. ];
  164. // echo has no return value while print has a return value of 1 so it can be used in expressions.
  165. // https://www.w3schools.com/php/php_echo_print.asp
  166. yield [
  167. '<?php
  168. $ret = print "test";
  169. ',
  170. ];
  171. yield [
  172. '<?php
  173. @print foo();
  174. ',
  175. ];
  176. yield [
  177. '<?php
  178. function testFunction() {
  179. return print("test");
  180. }
  181. $a = testFunction();
  182. $b += print($a);
  183. $c=\'\';
  184. $c .= $b.print($a);
  185. $d = print($c) > 0 ? \'a\' : \'b\';
  186. switch(print(\'a\')) {}
  187. if (1 === print($a)) {}
  188. ',
  189. ];
  190. yield [
  191. '<?php
  192. some_function_call();
  193. echo "test";
  194. ',
  195. '<?php
  196. some_function_call();
  197. print "test";
  198. ',
  199. ];
  200. yield [
  201. '<?php
  202. echo "test";
  203. ',
  204. '<?php
  205. print "test";
  206. ',
  207. ];
  208. yield [
  209. '<?php
  210. echo ("test");
  211. ',
  212. '<?php
  213. print ("test");
  214. ',
  215. ];
  216. yield [
  217. '<?php
  218. echo("test");
  219. ',
  220. '<?php
  221. print("test");
  222. ',
  223. ];
  224. yield [
  225. '<?php
  226. echo foo(1, 2);
  227. ',
  228. '<?php
  229. print foo(1, 2);
  230. ',
  231. ];
  232. yield [
  233. '<?php
  234. echo $foo ? "foo" : "bar";
  235. ',
  236. '<?php
  237. print $foo ? "foo" : "bar";
  238. ',
  239. ];
  240. yield [
  241. '<?php
  242. if ($foo) {
  243. echo "foo";
  244. }
  245. echo "bar";
  246. ',
  247. '<?php
  248. if ($foo) {
  249. print "foo";
  250. }
  251. print "bar";
  252. ',
  253. ];
  254. foreach (self::getCodeSnippetsToConvertBothWays() as $codeSnippet) {
  255. yield [
  256. sprintf($codeSnippet, 'echo'),
  257. sprintf($codeSnippet, 'print'),
  258. ];
  259. }
  260. }
  261. public function testDefaultConfig(): void
  262. {
  263. $this->fixer->configure([]);
  264. self::assertCandidateTokenType(T_PRINT, $this->fixer);
  265. }
  266. /**
  267. * @param array<mixed> $wrongConfig
  268. *
  269. * @dataProvider provideWrongConfigCases
  270. */
  271. public function testWrongConfig(array $wrongConfig, string $expectedMessage): void
  272. {
  273. $this->expectException(InvalidFixerConfigurationException::class);
  274. $this->expectExceptionMessageMatches($expectedMessage);
  275. $this->fixer->configure($wrongConfig);
  276. }
  277. public static function provideWrongConfigCases(): iterable
  278. {
  279. yield [
  280. ['a' => 'b'],
  281. '#^\[no_mixed_echo_print\] Invalid configuration: The option "a" does not exist\. (Known|Defined) options are: "use"\.$#',
  282. ];
  283. yield [
  284. ['a' => 'b', 'b' => 'c'],
  285. '#^\[no_mixed_echo_print\] Invalid configuration: The options "a", "b" do not exist\. (Known|Defined) options are: "use"\.$#',
  286. ];
  287. yield [
  288. [1],
  289. '#^\[no_mixed_echo_print\] Invalid configuration: The option "0" does not exist\. (Known|Defined) options are: "use"\.$#',
  290. ];
  291. yield [
  292. ['use' => '_invalid_'],
  293. '#^\[no_mixed_echo_print\] Invalid configuration: The option "use" with value "_invalid_" is invalid\. Accepted values are: "print", "echo"\.$#',
  294. ];
  295. }
  296. private static function assertCandidateTokenType(int $expected, AbstractFixer $fixer): void
  297. {
  298. $reflectionProperty = new \ReflectionProperty($fixer, 'candidateTokenType');
  299. $reflectionProperty->setAccessible(true);
  300. self::assertSame($expected, $reflectionProperty->getValue($fixer));
  301. }
  302. /**
  303. * @return iterable<non-empty-string>
  304. */
  305. private static function getCodeSnippetsToConvertBothWays(): iterable
  306. {
  307. yield 'inside of HTML' => '<div><?php %1$s "foo" ?></div>';
  308. yield 'foreach without curly brackets' => '<?php
  309. %1$s "There will be foos: ";
  310. foreach ($foos as $foo)
  311. %1$s $foo;
  312. %1$s "End of foos";
  313. ';
  314. yield 'if and else without curly brackets' => '<?php
  315. if ($foo)
  316. %1$s "One";
  317. elseif ($bar)
  318. %1$s "Two";
  319. else
  320. %1$s "Three";
  321. ';
  322. }
  323. }