FunctionDeclarationFixerTest.php 15 KB

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