FunctionDeclarationFixerTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  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\FunctionNotation;
  13. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  14. use PhpCsFixer\Fixer\FunctionNotation\FunctionDeclarationFixer;
  15. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  16. /**
  17. * @author Denis Sokolov <denis@sokolov.cc>
  18. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  19. *
  20. * @internal
  21. *
  22. * @covers \PhpCsFixer\Fixer\FunctionNotation\FunctionDeclarationFixer
  23. *
  24. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\FunctionNotation\FunctionDeclarationFixer>
  25. *
  26. * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\FunctionNotation\FunctionDeclarationFixer
  27. */
  28. final class FunctionDeclarationFixerTest extends AbstractFixerTestCase
  29. {
  30. /**
  31. * @var array<string, string>
  32. */
  33. private static array $configurationClosureSpacingNone = ['closure_function_spacing' => FunctionDeclarationFixer::SPACING_NONE];
  34. /**
  35. * @var array<string, string>
  36. */
  37. private static array $configurationArrowSpacingNone = ['closure_fn_spacing' => FunctionDeclarationFixer::SPACING_NONE];
  38. public function testInvalidConfigurationClosureFunctionSpacing(): void
  39. {
  40. $this->expectException(InvalidFixerConfigurationException::class);
  41. $this->expectExceptionMessageMatches(
  42. '#^\[function_declaration\] Invalid configuration: The option "closure_function_spacing" with value "neither" is invalid\. Accepted values are: "none", "one"\.$#'
  43. );
  44. $this->fixer->configure(['closure_function_spacing' => 'neither']); // @phpstan-ignore-line
  45. }
  46. public function testInvalidConfigurationClosureFnSpacing(): void
  47. {
  48. $this->expectException(InvalidFixerConfigurationException::class);
  49. $this->expectExceptionMessageMatches(
  50. '#^\[function_declaration\] Invalid configuration: The option "closure_fn_spacing" with value "neither" is invalid\. Accepted values are: "none", "one"\.$#'
  51. );
  52. $this->fixer->configure(['closure_fn_spacing' => 'neither']); // @phpstan-ignore-line
  53. }
  54. /**
  55. * @param _AutogeneratedInputConfiguration $configuration
  56. *
  57. * @dataProvider provideFixCases
  58. */
  59. public function testFix(string $expected, ?string $input = null, array $configuration = []): void
  60. {
  61. $this->fixer->configure($configuration);
  62. $this->doTest($expected, $input);
  63. }
  64. public static function provideFixCases(): iterable
  65. {
  66. yield [
  67. // non-PHP test
  68. 'function foo () {}',
  69. ];
  70. yield [
  71. '<?php function foo() {}',
  72. '<?php function foo() {}',
  73. ];
  74. yield [
  75. '<?php function foo() {}',
  76. '<?php function foo () {}',
  77. ];
  78. yield [
  79. '<?php function foo() {}',
  80. '<?php function foo () {}',
  81. ];
  82. yield [
  83. '<?php function foo() {}',
  84. '<?php function
  85. foo () {}',
  86. ];
  87. yield [
  88. '<?php function ($i) {};',
  89. '<?php function($i) {};',
  90. ];
  91. yield [
  92. '<?php function _function() {}',
  93. '<?php function _function () {}',
  94. ];
  95. yield [
  96. '<?php function foo($a, $b = true) {}',
  97. '<?php function foo($a, $b = true){}',
  98. ];
  99. yield [
  100. '<?php function foo($a, $b = true) {}',
  101. '<?php function foo($a, $b = true) {}',
  102. ];
  103. yield [
  104. '<?php function foo($a)
  105. {}',
  106. ];
  107. yield [
  108. '<?php function ($a) use ($b) {};',
  109. '<?php function ($a) use ($b) {};',
  110. ];
  111. yield [
  112. '<?php $foo = function ($foo) use ($bar, $baz) {};',
  113. '<?php $foo = function ($foo) use($bar, $baz) {};',
  114. ];
  115. yield [
  116. '<?php $foo = function ($foo) use ($bar, $baz) {};',
  117. '<?php $foo = function ($foo)use ($bar, $baz) {};',
  118. ];
  119. yield [
  120. '<?php $foo = function ($foo) use ($bar, $baz) {};',
  121. '<?php $foo = function ($foo)use($bar, $baz) {};',
  122. ];
  123. yield [
  124. '<?php function &foo($a) {}',
  125. '<?php function &foo( $a ) {}',
  126. ];
  127. yield [
  128. '<?php function foo($a)
  129. {}',
  130. '<?php function foo( $a)
  131. {}',
  132. ];
  133. yield [
  134. '<?php
  135. function foo(
  136. $a,
  137. $b,
  138. $c
  139. ) {}',
  140. ];
  141. yield [
  142. '<?php $function = function () {};',
  143. '<?php $function = function(){};',
  144. ];
  145. yield [
  146. '<?php $function("");',
  147. ];
  148. yield [
  149. '<?php function ($a) use ($b) {};',
  150. '<?php function($a)use($b) {};',
  151. ];
  152. yield [
  153. '<?php function ($a) use ($b) {};',
  154. '<?php function($a) use ($b) {};',
  155. ];
  156. yield [
  157. '<?php function ($a) use ($b) {};',
  158. '<?php function ($a) use ( $b ) {};',
  159. ];
  160. yield [
  161. '<?php function &($a) use ($b) {};',
  162. '<?php function &( $a ) use ( $b ) {};',
  163. ];
  164. yield [
  165. '<?php
  166. interface Foo
  167. {
  168. public function setConfig(ConfigInterface $config);
  169. }',
  170. ];
  171. // do not remove multiline space before { when end of previous line is a comment
  172. yield [
  173. '<?php
  174. function foo() // bar
  175. { // baz
  176. }',
  177. ];
  178. yield [
  179. '<?php
  180. function foo() /* bar */
  181. { /* baz */
  182. }',
  183. ];
  184. yield [
  185. // non-PHP test
  186. 'function foo () {}',
  187. null,
  188. self::$configurationClosureSpacingNone,
  189. ];
  190. yield [
  191. '<?php function foo() {}',
  192. '<?php function foo() {}',
  193. self::$configurationClosureSpacingNone,
  194. ];
  195. yield [
  196. '<?php function foo() {}',
  197. '<?php function foo () {}',
  198. self::$configurationClosureSpacingNone,
  199. ];
  200. yield [
  201. '<?php function foo() {}',
  202. '<?php function foo () {}',
  203. self::$configurationClosureSpacingNone,
  204. ];
  205. yield [
  206. '<?php function foo() {}',
  207. '<?php function
  208. foo () {}',
  209. self::$configurationClosureSpacingNone,
  210. ];
  211. yield [
  212. '<?php function($i) {};',
  213. null,
  214. self::$configurationClosureSpacingNone,
  215. ];
  216. yield [
  217. '<?php function _function() {}',
  218. '<?php function _function () {}',
  219. self::$configurationClosureSpacingNone,
  220. ];
  221. yield [
  222. '<?php function foo($a, $b = true) {}',
  223. '<?php function foo($a, $b = true){}',
  224. self::$configurationClosureSpacingNone,
  225. ];
  226. yield [
  227. '<?php function foo($a, $b = true) {}',
  228. '<?php function foo($a, $b = true) {}',
  229. self::$configurationClosureSpacingNone,
  230. ];
  231. yield [
  232. '<?php function foo($a)
  233. {}',
  234. null,
  235. self::$configurationClosureSpacingNone,
  236. ];
  237. yield [
  238. '<?php function($a) use ($b) {};',
  239. '<?php function ($a) use ($b) {};',
  240. self::$configurationClosureSpacingNone,
  241. ];
  242. yield [
  243. '<?php $foo = function($foo) use ($bar, $baz) {};',
  244. '<?php $foo = function ($foo) use($bar, $baz) {};',
  245. self::$configurationClosureSpacingNone,
  246. ];
  247. yield [
  248. '<?php $foo = function($foo) use ($bar, $baz) {};',
  249. '<?php $foo = function ($foo)use ($bar, $baz) {};',
  250. self::$configurationClosureSpacingNone,
  251. ];
  252. yield [
  253. '<?php $foo = function($foo) use ($bar, $baz) {};',
  254. '<?php $foo = function ($foo)use($bar, $baz) {};',
  255. self::$configurationClosureSpacingNone,
  256. ];
  257. yield [
  258. '<?php function &foo($a) {}',
  259. '<?php function &foo( $a ) {}',
  260. self::$configurationClosureSpacingNone,
  261. ];
  262. yield [
  263. '<?php function foo($a)
  264. {}',
  265. '<?php function foo( $a)
  266. {}',
  267. self::$configurationClosureSpacingNone,
  268. ];
  269. yield [
  270. '<?php
  271. function foo(
  272. $a,
  273. $b,
  274. $c
  275. ) {}',
  276. null,
  277. self::$configurationClosureSpacingNone,
  278. ];
  279. yield [
  280. '<?php $function = function() {};',
  281. '<?php $function = function (){};',
  282. self::$configurationClosureSpacingNone,
  283. ];
  284. yield [
  285. '<?php $function("");',
  286. null,
  287. self::$configurationClosureSpacingNone,
  288. ];
  289. yield [
  290. '<?php function($a) use ($b) {};',
  291. '<?php function ($a)use($b) {};',
  292. self::$configurationClosureSpacingNone,
  293. ];
  294. yield [
  295. '<?php function($a) use ($b) {};',
  296. '<?php function ($a) use ($b) {};',
  297. self::$configurationClosureSpacingNone,
  298. ];
  299. yield [
  300. '<?php function($a) use ($b) {};',
  301. '<?php function ($a) use ( $b ) {};',
  302. self::$configurationClosureSpacingNone,
  303. ];
  304. yield [
  305. '<?php function&($a) use ($b) {};',
  306. '<?php function &( $a ) use ( $b ) {};',
  307. self::$configurationClosureSpacingNone,
  308. ];
  309. yield [
  310. '<?php
  311. interface Foo
  312. {
  313. public function setConfig(ConfigInterface $config);
  314. }',
  315. null,
  316. self::$configurationClosureSpacingNone,
  317. ];
  318. // do not remove multiline space before { when end of previous line is a comment
  319. yield [
  320. '<?php
  321. function foo() // bar
  322. { // baz
  323. }',
  324. null,
  325. self::$configurationClosureSpacingNone,
  326. ];
  327. yield [
  328. '<?php
  329. function foo() /* bar */
  330. { /* baz */
  331. }',
  332. null,
  333. self::$configurationClosureSpacingNone,
  334. ];
  335. yield [
  336. '<?php function #
  337. foo#
  338. (#
  339. ) #
  340. {#
  341. }#',
  342. ];
  343. yield [
  344. '<?php
  345. $b = static function ($a) {
  346. echo $a;
  347. };
  348. ',
  349. '<?php
  350. $b = static function( $a ) {
  351. echo $a;
  352. };
  353. ',
  354. ];
  355. yield [
  356. '<?php
  357. $b = static function($a) {
  358. echo $a;
  359. };
  360. ',
  361. '<?php
  362. $b = static function ( $a ) {
  363. echo $a;
  364. };
  365. ',
  366. self::$configurationClosureSpacingNone,
  367. ];
  368. yield ['<?php use function Foo\bar; bar ( 1 );'];
  369. yield ['<?php use function some\test\{fn_a, fn_b, fn_c};'];
  370. yield ['<?php use function some\test\{fn_a, fn_b, fn_c} ?>'];
  371. yield ['<?php use function Foo\bar; bar ( 1 );', null, self::$configurationClosureSpacingNone];
  372. yield ['<?php use function some\test\{fn_a, fn_b, fn_c};', null, self::$configurationClosureSpacingNone];
  373. yield ['<?php use function some\test\{fn_a, fn_b, fn_c} ?>', null, self::$configurationClosureSpacingNone];
  374. yield [
  375. '<?php fn ($i) => null;',
  376. '<?php fn($i) => null;',
  377. ];
  378. yield [
  379. '<?php fn ($a) => null;',
  380. '<?php fn ($a) => null;',
  381. ];
  382. yield [
  383. '<?php $fn = fn () => null;',
  384. '<?php $fn = fn()=> null;',
  385. ];
  386. yield [
  387. '<?php fn &($a) => null;',
  388. '<?php fn &( $a ) => null;',
  389. ];
  390. yield [
  391. '<?php fn($i) => null;',
  392. null,
  393. self::$configurationArrowSpacingNone,
  394. ];
  395. yield [
  396. '<?php fn($a) => null;',
  397. '<?php fn ($a) => null;',
  398. self::$configurationArrowSpacingNone,
  399. ];
  400. yield [
  401. '<?php $fn = fn() => null;',
  402. '<?php $fn = fn ()=> null;',
  403. self::$configurationArrowSpacingNone,
  404. ];
  405. yield [
  406. '<?php $fn("");',
  407. null,
  408. self::$configurationArrowSpacingNone,
  409. ];
  410. yield [
  411. '<?php fn&($a) => null;',
  412. '<?php fn &( $a ) => null;',
  413. self::$configurationArrowSpacingNone,
  414. ];
  415. yield [
  416. '<?php fn&($a,$b) => null;',
  417. '<?php fn &( $a,$b ) => null;',
  418. self::$configurationArrowSpacingNone,
  419. ];
  420. yield [
  421. '<?php $b = static fn ($a) => $a;',
  422. '<?php $b = static fn( $a ) => $a;',
  423. ];
  424. yield [
  425. '<?php $b = static fn($a) => $a;',
  426. '<?php $b = static fn ( $a ) => $a;',
  427. self::$configurationArrowSpacingNone,
  428. ];
  429. }
  430. /**
  431. * @param _AutogeneratedInputConfiguration $configuration
  432. *
  433. * @dataProvider provideFixPhp80Cases
  434. *
  435. * @requires PHP 8.0
  436. */
  437. public function testFixPhp80(string $expected, ?string $input = null, array $configuration = []): void
  438. {
  439. $this->fixer->configure($configuration);
  440. $this->doTest($expected, $input);
  441. }
  442. public static function provideFixPhp80Cases(): iterable
  443. {
  444. yield [
  445. '<?php function ($i) {};',
  446. '<?php function( $i, ) {};',
  447. ];
  448. yield [
  449. '<?php function (
  450. $a,
  451. $b,
  452. $c,
  453. ) {};',
  454. '<?php function(
  455. $a,
  456. $b,
  457. $c,
  458. ) {};',
  459. ];
  460. yield [
  461. '<?php function foo(
  462. $a,
  463. $b,
  464. $c,
  465. ) {}',
  466. '<?php function foo (
  467. $a,
  468. $b,
  469. $c,
  470. ){}',
  471. ];
  472. yield [
  473. '<?php
  474. $b = static function ($a,$b) {
  475. echo $a;
  476. };
  477. ',
  478. '<?php
  479. $b = static function( $a,$b, ) {
  480. echo $a;
  481. };
  482. ',
  483. ];
  484. yield [
  485. '<?php fn&($a,$b) => null;',
  486. '<?php fn &( $a,$b, ) => null;',
  487. self::$configurationArrowSpacingNone,
  488. ];
  489. yield [
  490. '<?php
  491. function ($a) use ($b) {};
  492. function ($y) use (
  493. $b,
  494. $c,
  495. ) {};
  496. ',
  497. '<?php
  498. function ($a) use ($b , ) {};
  499. function ($y) use (
  500. $b,
  501. $c,
  502. ) {};
  503. ',
  504. ];
  505. yield [
  506. '<?php function ($i,) {};',
  507. '<?php function( $i, ) {};',
  508. ['trailing_comma_single_line' => true],
  509. ];
  510. }
  511. }