FunctionToConstantFixerTest.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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\LanguageConstruct;
  13. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  14. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  15. /**
  16. * @internal
  17. *
  18. * @covers \PhpCsFixer\Fixer\LanguageConstruct\FunctionToConstantFixer
  19. */
  20. final class FunctionToConstantFixerTest extends AbstractFixerTestCase
  21. {
  22. /**
  23. * @param array<string, mixed> $config
  24. *
  25. * @dataProvider provideFixCases
  26. */
  27. public function testFix(string $expected, ?string $input = null, array $config = []): void
  28. {
  29. $this->fixer->configure($config);
  30. $this->doTest($expected, $input);
  31. }
  32. public static function provideFixCases(): iterable
  33. {
  34. return [
  35. 'Minimal case, alternative casing, alternative statement end.' => [
  36. '<?php echo PHP_VERSION?>',
  37. '<?php echo PHPversion()?>',
  38. ],
  39. 'With embedded comment.' => [
  40. '<?php echo PHP_VERSION/**/?>',
  41. '<?php echo phpversion(/**/)?>',
  42. ],
  43. 'With white space.' => [
  44. '<?php echo PHP_VERSION ;',
  45. '<?php echo phpversion ( ) ;',
  46. ],
  47. 'With multi line whitespace.' => [
  48. '<?php echo
  49. PHP_VERSION
  50. '.'
  51. '.'
  52. ;',
  53. '<?php echo
  54. phpversion
  55. (
  56. )
  57. ;',
  58. ],
  59. 'Global namespaced.' => [
  60. '<?php echo \PHP_VERSION;',
  61. '<?php echo \phpversion();',
  62. ],
  63. 'Wrong number of arguments.' => [
  64. '<?php phpversion($a);',
  65. ],
  66. 'Wrong namespace.' => [
  67. '<?php A\B\phpversion();',
  68. ],
  69. 'Class creating.' => [
  70. '<?php new phpversion();',
  71. ],
  72. 'Class static method call.' => [
  73. '<?php A::phpversion();',
  74. ],
  75. 'Class method call.' => [
  76. '<?php $a->phpversion();',
  77. ],
  78. 'Overridden function.' => [
  79. '<?php if (!function_exists("phpversion")){function phpversion(){}}?>',
  80. ],
  81. 'phpversion only' => [
  82. '<?php echo PHP_VERSION; echo php_sapi_name(); echo pi();',
  83. '<?php echo phpversion(); echo php_sapi_name(); echo pi();',
  84. ['functions' => ['phpversion']],
  85. ],
  86. 'php_sapi_name only' => [
  87. '<?php echo phpversion(); echo PHP_SAPI; echo pi();',
  88. '<?php echo phpversion(); echo php_sapi_name(); echo pi();',
  89. ['functions' => ['php_sapi_name']],
  90. ],
  91. 'php_sapi_name in conditional' => [
  92. '<?php if ("cli" === PHP_SAPI && $a){ echo 123;}',
  93. '<?php if ("cli" === php_sapi_name() && $a){ echo 123;}',
  94. ['functions' => ['php_sapi_name']],
  95. ],
  96. 'pi only' => [
  97. '<?php echo phpversion(); echo php_sapi_name(); echo M_PI;',
  98. '<?php echo phpversion(); echo php_sapi_name(); echo pi();',
  99. ['functions' => ['pi']],
  100. ],
  101. 'multi line pi' => [
  102. '<?php
  103. $a =
  104. $b
  105. || $c < M_PI
  106. ;',
  107. '<?php
  108. $a =
  109. $b
  110. || $c < pi()
  111. ;',
  112. ['functions' => ['pi']],
  113. ],
  114. 'phpversion and pi' => [
  115. '<?php echo PHP_VERSION; echo php_sapi_name(); echo M_PI;',
  116. '<?php echo phpversion(); echo php_sapi_name(); echo M_PI;',
  117. ['functions' => ['pi', 'phpversion']],
  118. ],
  119. 'diff argument count than native allows' => [
  120. '<?php
  121. echo phpversion(1);
  122. echo php_sapi_name(1,2);
  123. echo pi(1);
  124. ',
  125. ],
  126. 'get_class => T_CLASS' => [
  127. '<?php
  128. class A
  129. {
  130. public function echoClassName($notMe)
  131. {
  132. echo get_class($notMe);
  133. echo __CLASS__/** 1 *//* 2 */;
  134. echo __CLASS__;
  135. }
  136. }
  137. class B
  138. {
  139. use A;
  140. }
  141. ',
  142. '<?php
  143. class A
  144. {
  145. public function echoClassName($notMe)
  146. {
  147. echo get_class($notMe);
  148. echo get_class(/** 1 *//* 2 */);
  149. echo GET_Class();
  150. }
  151. }
  152. class B
  153. {
  154. use A;
  155. }
  156. ',
  157. ],
  158. 'get_class with leading backslash' => [
  159. '<?php __CLASS__;',
  160. '<?php \get_class();',
  161. ],
  162. [
  163. '<?php class A { function B(){ echo static::class; }}',
  164. '<?php class A { function B(){ echo get_called_class(); }}',
  165. ['functions' => ['get_called_class']],
  166. ],
  167. [
  168. '<?php class A { function B(){
  169. echo#.
  170. #0
  171. static::class#1
  172. #2
  173. #3
  174. #4
  175. #5
  176. #6
  177. ;#7
  178. }}
  179. ',
  180. '<?php class A { function B(){
  181. echo#.
  182. #0
  183. get_called_class#1
  184. #2
  185. (#3
  186. #4
  187. )#5
  188. #6
  189. ;#7
  190. }}
  191. ',
  192. ['functions' => ['get_called_class']],
  193. ],
  194. 'get_called_class with leading backslash' => [
  195. '<?php class A { function B(){echo static::class; }}',
  196. '<?php class A { function B(){echo \get_called_class(); }}',
  197. ['functions' => ['get_called_class']],
  198. ],
  199. 'get_called_class overridden' => [
  200. '<?php echo get_called_class(1);',
  201. null,
  202. ['functions' => ['get_called_class']],
  203. ],
  204. [
  205. '<?php class Foo{ public function Bar(){ echo static::class ; }}',
  206. '<?php class Foo{ public function Bar(){ echo get_class( $This ); }}',
  207. ['functions' => ['get_class_this']],
  208. ],
  209. [
  210. '<?php class Foo{ public function Bar(){ echo static::class; get_class(1, 2); get_class($a); get_class($a, $b);}}',
  211. '<?php class Foo{ public function Bar(){ echo get_class($this); get_class(1, 2); get_class($a); get_class($a, $b);}}',
  212. ['functions' => ['get_class_this']],
  213. ],
  214. [
  215. '<?php class Foo{ public function Bar(){ echo static::class /* 0 */ /* 1 */ ;}}',
  216. '<?php class Foo{ public function Bar(){ echo \get_class( /* 0 */ $this /* 1 */ );}}',
  217. ['functions' => ['get_class_this']],
  218. ],
  219. [
  220. '<?php class Foo{ public function Bar(){ echo static::class; echo __CLASS__; }}',
  221. '<?php class Foo{ public function Bar(){ echo \get_class((($this))); echo get_class(); }}',
  222. ['functions' => ['get_class_this', 'get_class']],
  223. ],
  224. [
  225. '<?php
  226. class Foo{ public function Bar(){ echo $reflection = new \ReflectionClass(get_class($this->extension)); }}
  227. class Foo{ public function Bar(){ echo $reflection = new \ReflectionClass(get_class($this() )); }}
  228. ',
  229. null,
  230. ['functions' => ['get_class_this']],
  231. ],
  232. [
  233. "<?php namespace Foo;\nfunction &PHPversion(){}",
  234. ],
  235. ];
  236. }
  237. /**
  238. * @param array<mixed> $config
  239. *
  240. * @dataProvider provideInvalidConfigurationKeysCases
  241. */
  242. public function testInvalidConfigurationKeys(array $config): void
  243. {
  244. $this->expectException(InvalidFixerConfigurationException::class);
  245. $this->expectExceptionMessageMatches('#^\[function_to_constant\] Invalid configuration: The option "functions" with value array is invalid\.$#');
  246. $this->fixer->configure($config);
  247. }
  248. public static function provideInvalidConfigurationKeysCases(): iterable
  249. {
  250. return [
  251. [['functions' => ['a']]],
  252. [['functions' => [false => 1]]],
  253. [['functions' => ['abc' => true]]],
  254. ];
  255. }
  256. public function testInvalidConfigurationValue(): void
  257. {
  258. $this->expectException(InvalidFixerConfigurationException::class);
  259. $this->expectExceptionMessageMatches('#^\[function_to_constant\] Invalid configuration: The option "0" does not exist\. Defined options are: "functions"\.$#');
  260. // @phpstan-ignore-next-line
  261. $this->fixer->configure(['pi123']);
  262. }
  263. /**
  264. * @dataProvider provideFix81Cases
  265. *
  266. * @requires PHP 8.1
  267. */
  268. public function testFix81(string $expected, string $input = null): void
  269. {
  270. $this->doTest($expected, $input);
  271. }
  272. public static function provideFix81Cases(): iterable
  273. {
  274. yield 'first callable class' => [
  275. '<?php $a = get_class(...);',
  276. ];
  277. }
  278. }