NoExtraBlankLinesFixerTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  1. <?php
  2. /*
  3. * This file is part of PHP CS Fixer.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. namespace PhpCsFixer\Tests\Fixer\Whitespace;
  12. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  13. use PhpCsFixer\WhitespacesFixerConfig;
  14. /**
  15. * @internal
  16. *
  17. * @covers \PhpCsFixer\Fixer\Whitespace\NoExtraBlankLinesFixer
  18. */
  19. final class NoExtraBlankLinesFixerTest extends AbstractFixerTestCase
  20. {
  21. private $template = <<<'EOF'
  22. <?php
  23. use \DateTime;
  24. use \stdClass;
  25. use \InvalidArgumentException;
  26. class Test {
  27. public function testThrow($a)
  28. {
  29. if ($a) {
  30. throw new InvalidArgumentException('test.'); // test
  31. }
  32. $date = new DateTime();
  33. $class = new stdClass();
  34. $class = (string) $class;
  35. $e = new InvalidArgumentException($class.$date->format('Y'));
  36. throw $e;
  37. }
  38. public function testBreak($a)
  39. {
  40. switch($a) {
  41. case 1:
  42. echo $a;
  43. break;
  44. case 2:
  45. echo 'test';
  46. break;
  47. }
  48. }
  49. protected static function testContinueAndReturn($a, $b)
  50. {
  51. while($a < 100) {
  52. if ($b < time()) {
  53. continue;
  54. }
  55. return $b;
  56. }
  57. return $a;
  58. }
  59. private function test(){
  60. // comment
  61. }
  62. private function test123(){
  63. // comment
  64. }
  65. }
  66. EOF;
  67. /**
  68. * @group legacy
  69. * @expectedDeprecation Passing NULL to set default configuration is deprecated and will not be supported in 3.0, use an empty array instead.
  70. */
  71. public function testLegacyConfigNull()
  72. {
  73. $this->fixer->configure(null);
  74. $this->doTest($this->removeLinesFromString($this->template, [23, 24]), $this->template);
  75. }
  76. /**
  77. * @param int[] $lineNumberRemoved Line numbers expected to be removed after fixing
  78. *
  79. * @group legacy
  80. * @dataProvider provideWithConfigCases
  81. * @expectedDeprecation Passing "tokens" at the root of the configuration for rule "no_extra_blank_lines" is deprecated and will not be supported in 3.0, use "tokens" => array(...) option instead.
  82. */
  83. public function testLegacyWithConfig(array $lineNumberRemoved, array $config)
  84. {
  85. $this->fixer->configure($config);
  86. $this->doTest($this->removeLinesFromString($this->template, $lineNumberRemoved), $this->template);
  87. }
  88. /**
  89. * @param int[] $lineNumberRemoved Line numbers expected to be removed after fixing
  90. *
  91. * @dataProvider provideWithConfigCases
  92. */
  93. public function testWithConfig(array $lineNumberRemoved, array $config)
  94. {
  95. $this->fixer->configure(['tokens' => $config]);
  96. $this->doTest($this->removeLinesFromString($this->template, $lineNumberRemoved), $this->template);
  97. }
  98. public function provideWithConfigCases()
  99. {
  100. $tests = [
  101. [
  102. [9, 14, 21, 43, 45, 49, 53, 57],
  103. ['curly_brace_block'],
  104. ],
  105. [
  106. [3, 5],
  107. ['use'],
  108. ],
  109. [
  110. [23, 24],
  111. ['extra'],
  112. ],
  113. [
  114. [49, 53],
  115. ['return'],
  116. ],
  117. [
  118. [45],
  119. ['continue'],
  120. ],
  121. [
  122. [32],
  123. ['break'],
  124. ],
  125. [
  126. [14, 21],
  127. ['throw'],
  128. ],
  129. ];
  130. $all = [[], []];
  131. foreach ($tests as $test) {
  132. $all[0] = array_merge($test[0], $all[0]);
  133. $all[1] = array_merge($test[1], $all[1]);
  134. }
  135. $tests[] = $all;
  136. return $tests;
  137. }
  138. public function testFix()
  139. {
  140. $expected = <<<'EOF'
  141. <?php
  142. $a = new Bar();
  143. $a = new FooBaz();
  144. EOF;
  145. $input = <<<'EOF'
  146. <?php
  147. $a = new Bar();
  148. $a = new FooBaz();
  149. EOF;
  150. $this->doTest($expected, $input);
  151. }
  152. public function testFixWithManyEmptyLines()
  153. {
  154. $expected = <<<'EOF'
  155. <?php
  156. $a = new Bar();
  157. $a = new FooBaz();
  158. EOF;
  159. $input = <<<'EOF'
  160. <?php
  161. $a = new Bar();
  162. $a = new FooBaz();
  163. EOF;
  164. $this->doTest($expected, $input);
  165. }
  166. public function testFixWithHeredoc()
  167. {
  168. $expected = '
  169. <?php
  170. $b = <<<TEXT
  171. Foo TEXT
  172. Bar
  173. FooFoo
  174. TEXT;
  175. ';
  176. $this->doTest($expected);
  177. }
  178. public function testFixWithNowdoc()
  179. {
  180. $expected = '
  181. <?php
  182. $b = <<<\'TEXT\'
  183. Foo TEXT;
  184. Bar1}
  185. FooFoo
  186. TEXT;
  187. ';
  188. $this->doTest($expected);
  189. }
  190. public function testFixWithEncapsulatedNowdoc()
  191. {
  192. $expected = '
  193. <?php
  194. $b = <<<\'TEXT\'
  195. Foo TEXT
  196. Bar
  197. <<<\'TEMPLATE\'
  198. BarFooBar TEMPLATE
  199. TEMPLATE;
  200. FooFoo
  201. TEXT;
  202. ';
  203. $this->doTest($expected);
  204. }
  205. public function testFixWithMultilineString()
  206. {
  207. $expected = <<<'EOF'
  208. <?php
  209. $a = 'Foo
  210. Bar';
  211. EOF;
  212. $this->doTest($expected);
  213. }
  214. public function testFixWithTrickyMultilineStrings()
  215. {
  216. $expected = <<<'EOF'
  217. <?php
  218. $a = 'Foo';
  219. $b = 'Bar
  220. Here\'s an escaped quote '
  221. .
  222. '
  223. FooFoo';
  224. EOF;
  225. $input = <<<'EOF'
  226. <?php
  227. $a = 'Foo';
  228. $b = 'Bar
  229. Here\'s an escaped quote '
  230. .
  231. '
  232. FooFoo';
  233. EOF;
  234. $this->doTest($expected, $input);
  235. }
  236. public function testFixWithCommentWithQuote()
  237. {
  238. $expected = <<<'EOF'
  239. <?php
  240. $a = 'foo';
  241. // my comment's must have a quote
  242. $b = 'foobar';
  243. $c = 'bar';
  244. EOF;
  245. $input = <<<'EOF'
  246. <?php
  247. $a = 'foo';
  248. // my comment's must have a quote
  249. $b = 'foobar';
  250. $c = 'bar';
  251. EOF;
  252. $this->doTest($expected, $input);
  253. }
  254. public function testFixWithTrailingInlineBlock()
  255. {
  256. $expected = "
  257. <?php
  258. echo 'hello';
  259. ?>
  260. \$a = 0;
  261. //a
  262. <?php
  263. \$a = 0;
  264. \$b = 1;
  265. //a
  266. ?>
  267. ";
  268. $this->doTest($expected);
  269. }
  270. /**
  271. * @param string $expected
  272. * @param string $input
  273. *
  274. * @dataProvider provideCommentCases
  275. */
  276. public function testFixWithComments($expected, $input)
  277. {
  278. $this->doTest($expected, $input);
  279. }
  280. public function provideCommentCases()
  281. {
  282. return [
  283. [
  284. <<<'EOF'
  285. <?php
  286. //class Test
  287. $a; //
  288. $b;
  289. /***/
  290. $c;
  291. //
  292. $d;
  293. EOF
  294. ,
  295. <<<'EOF'
  296. <?php
  297. //class Test
  298. $a; //
  299. $b;
  300. /***/
  301. $c;
  302. //
  303. $d;
  304. EOF
  305. ],
  306. [
  307. "<?php\n//a\n\n\$a =1;",
  308. "<?php\n//a\n\n\n\n\$a =1;",
  309. ],
  310. ];
  311. }
  312. /**
  313. * @param string $expected
  314. * @param null|string $input
  315. *
  316. * @dataProvider provideLineBreakCases
  317. */
  318. public function testFixWithLineBreaks($expected, $input = null)
  319. {
  320. $this->doTest($expected, $input);
  321. }
  322. public function provideLineBreakCases()
  323. {
  324. $input = '<?php //
  325. $a = 1;
  326. $b = 1;
  327. ';
  328. $expected = '<?php //
  329. $a = 1;
  330. $b = 1;
  331. ';
  332. return [
  333. [
  334. "<?php\r\n//a\r\n\r\n\$a =1;",
  335. "<?php\r\n//a\r\n\r\n\r\n\r\n\$a =1;",
  336. ],
  337. [
  338. $expected,
  339. $input,
  340. ],
  341. [
  342. str_replace("\n", "\r\n", $expected),
  343. str_replace("\n", "\r\n", $input),
  344. ],
  345. [
  346. str_replace("\n", "\r", $input),
  347. ],
  348. [
  349. str_replace("\n", "\r", $expected),
  350. ],
  351. ];
  352. }
  353. public function testWrongConfig()
  354. {
  355. $this->expectException(\PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException::class);
  356. $this->expectExceptionMessageMatches('/^\[no_extra_blank_lines\] Invalid configuration: The option "tokens" .*\.$/');
  357. $this->fixer->configure(['tokens' => ['__TEST__']]);
  358. }
  359. /**
  360. * @param string $expected
  361. * @param null|string $input
  362. *
  363. * @dataProvider provideBetweenUseCases
  364. */
  365. public function testBetweenUse($expected, $input = null)
  366. {
  367. $this->fixer->configure(['tokens' => ['use']]);
  368. $this->doTest($expected, $input);
  369. }
  370. public function provideBetweenUseCases()
  371. {
  372. return [
  373. ['<?php use A\B;'],
  374. ['<?php use A\B?>'],
  375. ['<?php use A\B;use A\D; return 1;'],
  376. ["<?php use A\\B?>\n\n<?php use D\\E\\F?>"],
  377. ['<?php use Y\B;use A\D; return 1;'],
  378. [
  379. '<?php
  380. use A\B;
  381. use A\C;',
  382. '<?php
  383. use A\B;
  384. use A\C;',
  385. ],
  386. [
  387. '<?php use A\E;use A\Z;
  388. use C;
  389. return 1;
  390. ',
  391. '<?php use A\E;use A\Z;
  392. use C;
  393. return 1;
  394. ',
  395. ],
  396. [
  397. '<?php
  398. class Test {
  399. use A;
  400. use B;
  401. }',
  402. ],
  403. [
  404. '<?php
  405. $example = function () use ($message) { var_dump($message); };
  406. $example = function () use ($message) { var_dump($message); };
  407. ',
  408. ],
  409. ];
  410. }
  411. public function testRemoveLinesBetweenUseStatements()
  412. {
  413. $expected = <<<'EOF'
  414. <?php
  415. use Zxy\Qux;
  416. use Zoo\Bar as Bar2;
  417. use Foo\Bar as Bar1;
  418. use Foo\Zar\Baz;
  419. $c = 1;
  420. use Foo\Quxx as Quxx1;
  421. use Foo\Zar\Quxx;
  422. $a = new Bar1();
  423. $a = new Bar2();
  424. $a = new Baz();
  425. $a = new Qux();
  426. EOF
  427. ;
  428. $input = <<<'EOF'
  429. <?php
  430. use Zxy\Qux;
  431. use Zoo\Bar as Bar2;
  432. use Foo\Bar as Bar1;
  433. use Foo\Zar\Baz;
  434. $c = 1;
  435. use Foo\Quxx as Quxx1;
  436. use Foo\Zar\Quxx;
  437. $a = new Bar1();
  438. $a = new Bar2();
  439. $a = new Baz();
  440. $a = new Qux();
  441. EOF
  442. ;
  443. $this->fixer->configure(['tokens' => ['use']]);
  444. $this->doTest($expected, $input);
  445. }
  446. /**
  447. * @param string $expected
  448. * @param null|string $input
  449. *
  450. * @dataProvider provideRemoveLinesBetweenUseStatements70Cases
  451. * @requires PHP 7.0
  452. */
  453. public function testRemoveLinesBetweenUseStatements70($expected, $input = null)
  454. {
  455. $this->fixer->configure(['tokens' => ['use']]);
  456. $this->doTest($expected, $input);
  457. }
  458. public function provideRemoveLinesBetweenUseStatements70Cases()
  459. {
  460. return [
  461. [
  462. '<?php
  463. use some\a\{ClassA, ClassB, ClassC as C};
  464. use function some\a\{fn_a, fn_b, fn_c};
  465. use const some\a\{ConstA, ConstB, ConstC};
  466. ',
  467. '<?php
  468. use some\a\{ClassA, ClassB, ClassC as C};
  469. use function some\a\{fn_a, fn_b, fn_c};
  470. use const some\a\{ConstA, ConstB, ConstC};
  471. ',
  472. ],
  473. ];
  474. }
  475. /**
  476. * @param string $expected
  477. *
  478. * @dataProvider provideWithoutUsesCases
  479. */
  480. public function testWithoutUses($expected)
  481. {
  482. $this->fixer->configure(['tokens' => ['use']]);
  483. $this->doTest($expected);
  484. }
  485. public function provideWithoutUsesCases()
  486. {
  487. return [
  488. [
  489. '<?php
  490. $c = 1;
  491. $a = new Baz();
  492. $a = new Qux();',
  493. ],
  494. [
  495. '<?php use A\B;',
  496. ],
  497. [
  498. '<?php use A\B?>',
  499. ],
  500. [
  501. '<?php use A\B;?>',
  502. ],
  503. ];
  504. }
  505. /**
  506. * @dataProvider provideRemoveBetweenUseTraitsCases
  507. *
  508. * @param string $expected
  509. * @param string $input
  510. */
  511. public function testRemoveBetweenUseTraits($expected, $input)
  512. {
  513. $this->fixer->configure(['tokens' => ['use_trait']]);
  514. $this->doTest($expected, $input);
  515. }
  516. public function provideRemoveBetweenUseTraitsCases()
  517. {
  518. yield [
  519. '<?php
  520. class Foo
  521. {
  522. use Z; // 123
  523. use Bar;/* */use Baz;
  524. public function baz() {}
  525. use Bar1; use Baz1;
  526. public function baz1() {}
  527. }
  528. ',
  529. '<?php
  530. class Foo
  531. {
  532. use Z; // 123
  533. use Bar;/* */use Baz;
  534. public function baz() {}
  535. use Bar1; use Baz1;
  536. public function baz1() {}
  537. }
  538. ',
  539. ];
  540. yield [
  541. '<?php
  542. class Foo
  543. {
  544. use Bar;use Baz;
  545. use Bar1;use Baz1;
  546. public function baz() {}
  547. }
  548. ',
  549. '<?php
  550. class Foo
  551. {
  552. use Bar;use Baz;
  553. use Bar1;use Baz1;
  554. public function baz() {}
  555. }
  556. ',
  557. ];
  558. yield [
  559. '<?php
  560. namespace T\A;
  561. use V;
  562. use W;
  563. class Test {
  564. use A;
  565. use B;
  566. private function test($b) {
  567. $a = function() use ($b) { echo $b;};
  568. $b = function() use ($b) { echo $b;};
  569. }
  570. }',
  571. '<?php
  572. namespace T\A;
  573. use V;
  574. use W;
  575. class Test {
  576. use A;
  577. use B;
  578. private function test($b) {
  579. $a = function() use ($b) { echo $b;};
  580. $b = function() use ($b) { echo $b;};
  581. }
  582. }',
  583. ];
  584. }
  585. /**
  586. * @group legacy
  587. * @expectedDeprecation Token "useTrait" in option "tokens" for rule "no_extra_blank_lines" is deprecated and will be removed in 3.0, use "use_trait" instead.
  588. */
  589. public function testRemoveBetweenUseTraitsDeprecatedToken()
  590. {
  591. $this->fixer->configure(['tokens' => ['useTrait']]);
  592. $this->doTest(
  593. '<?php
  594. namespace T\A;
  595. use V;
  596. use W;
  597. class Test {
  598. use A;
  599. use B;
  600. private function test($b) {
  601. $a = function() use ($b) { echo $b;};
  602. $b = function() use ($b) { echo $b;};
  603. }
  604. }',
  605. '<?php
  606. namespace T\A;
  607. use V;
  608. use W;
  609. class Test {
  610. use A;
  611. use B;
  612. private function test($b) {
  613. $a = function() use ($b) { echo $b;};
  614. $b = function() use ($b) { echo $b;};
  615. }
  616. }'
  617. );
  618. }
  619. /**
  620. * @param string $expected
  621. * @param null|string $input
  622. *
  623. * @dataProvider provideOneAndInLineCases
  624. */
  625. public function testOneOrInLineCases($expected, $input = null)
  626. {
  627. $this->fixer->configure(['tokens' => [
  628. 'break',
  629. 'continue',
  630. 'return',
  631. 'throw',
  632. 'curly_brace_block',
  633. 'square_brace_block',
  634. 'parenthesis_brace_block',
  635. ]]);
  636. $this->doTest($expected, $input);
  637. }
  638. public function provideOneAndInLineCases()
  639. {
  640. $tests = [
  641. [
  642. "<?php\n\n\$a = function() use (\$b) { while(3<1)break; \$c = \$b[1]; while(\$b<1)continue; if (true) throw \$e; return 1; };\n\n",
  643. ],
  644. [
  645. "<?php throw new \\Exception('do not import.');\n",
  646. "<?php throw new \\Exception('do not import.');\n\n",
  647. ],
  648. [
  649. "<?php\n\n\$a = \$b[0];\n\n",
  650. ],
  651. [
  652. "<?php\n\n\$a->{'Test'};\nfunction test(){}\n",
  653. ],
  654. ];
  655. foreach ($tests as $index => $test) {
  656. yield $index => $test;
  657. }
  658. if (\PHP_VERSION_ID < 80000) {
  659. yield [
  660. "<?php\n\n\$a = \$b{0};\n\n",
  661. ];
  662. }
  663. }
  664. /**
  665. * @param string $expected
  666. * @param null|string $input
  667. *
  668. * @dataProvider provideOneAndInLine70Cases
  669. * @requires PHP 7.0
  670. */
  671. public function testOneOrInLine70Cases($expected, $input = null)
  672. {
  673. $this->fixer->configure(['tokens' => [
  674. 'break',
  675. 'continue',
  676. 'return',
  677. 'throw',
  678. 'curly_brace_block',
  679. 'square_brace_block',
  680. 'parenthesis_brace_block',
  681. ]]);
  682. $this->doTest($expected, $input);
  683. }
  684. public function provideOneAndInLine70Cases()
  685. {
  686. return [
  687. [
  688. "<?php\n\n\$a = new class { public function a () { while(4<1)break; while(3<1)continue; if (true) throw \$e; return 1; }};\n\n",
  689. ],
  690. ];
  691. }
  692. /**
  693. * @param string $expected
  694. * @param null|string $input
  695. *
  696. * @dataProvider provideBraceCases
  697. */
  698. public function testBraces(array $config, $expected, $input = null)
  699. {
  700. $this->fixer->configure($config);
  701. $this->doTest($expected, $input);
  702. }
  703. public function provideBraceCases()
  704. {
  705. return [
  706. [
  707. ['tokens' => ['curly_brace_block']],
  708. "<?php function test()\n\n{}\n\necho 789;",
  709. ],
  710. [
  711. ['tokens' => ['curly_brace_block']],
  712. "<?php switch(\$a){\ncase 1:echo 789;}",
  713. "<?php switch(\$a){\n \ncase 1:echo 789;}",
  714. ],
  715. [
  716. ['tokens' => ['parenthesis_brace_block']],
  717. '<?php
  718. is_int(
  719. 1);
  720. function test(
  721. $a,
  722. $b,
  723. $c
  724. )
  725. {
  726. }',
  727. '<?php
  728. is_int(
  729. 1);
  730. function test(
  731. $a,
  732. $b,
  733. $c
  734. )
  735. {
  736. }',
  737. ],
  738. [
  739. ['tokens' => ['parenthesis_brace_block']],
  740. "<?php array(\n1,\n2,\n3,\n);",
  741. "<?php array(\n \n1,\n2,\n3,\n\n\n);",
  742. ],
  743. [
  744. ['tokens' => ['parenthesis_brace_block']],
  745. '<?php
  746. function a()
  747. {
  748. $b->d(e(
  749. ));
  750. foreach ($a as $x) {
  751. }
  752. }',
  753. ],
  754. [
  755. ['tokens' => ['return']],
  756. '<?php
  757. class Foo
  758. {
  759. public function bar() {return 1;}
  760. public function baz() {return 2;
  761. }
  762. }',
  763. '<?php
  764. class Foo
  765. {
  766. public function bar() {return 1;}
  767. public function baz() {return 2;
  768. }
  769. }',
  770. ],
  771. [
  772. ['tokens' => ['square_brace_block']],
  773. "<?php \$c = \$b[0];\n\n\n\$a = [\n 1,\n2];\necho 1;\n\$b = [];\n\n\n//a\n",
  774. "<?php \$c = \$b[0];\n\n\n\$a = [\n\n 1,\n2];\necho 1;\n\$b = [];\n\n\n//a\n",
  775. ],
  776. ];
  777. }
  778. /**
  779. * @param string $expected
  780. * @param null|string $input
  781. *
  782. * @dataProvider provideMessyWhitespacesCases
  783. */
  784. public function testMessyWhitespaces(array $config, $expected, $input = null)
  785. {
  786. $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n"));
  787. $this->fixer->configure($config);
  788. $this->doTest($expected, $input);
  789. }
  790. public function provideMessyWhitespacesCases()
  791. {
  792. return [
  793. [
  794. [],
  795. "<?php\r\nuse AAA;\r\n\r\nuse BBB;\r\n\r\n",
  796. "<?php\r\nuse AAA;\r\n\r\n\r\n\r\nuse BBB;\r\n\r\n",
  797. ],
  798. [
  799. ['tokens' => ['parenthesis_brace_block']],
  800. "<?php is_int(\r\n1);",
  801. "<?php is_int(\r\n\r\n\r\n\r\n1);",
  802. ],
  803. [
  804. ['tokens' => ['square_brace_block']],
  805. "<?php \$c = \$b[0];\r\n\r\n\r\n\$a = [\r\n 1,\r\n2];\r\necho 1;\r\n\$b = [];\r\n\r\n\r\n//a\r\n",
  806. "<?php \$c = \$b[0];\r\n\r\n\r\n\$a = [\r\n\r\n 1,\r\n2];\r\necho 1;\r\n\$b = [];\r\n\r\n\r\n//a\r\n",
  807. ],
  808. [
  809. ['tokens' => ['square_brace_block']],
  810. "<?php \$c = \$b[0];\r\n\r\n\r\n\$a = [\r\n\t1,\r\n2];",
  811. "<?php \$c = \$b[0];\r\n\r\n\r\n\$a = [\r\n\r\n\t1,\r\n2];",
  812. ],
  813. ];
  814. }
  815. /**
  816. * @param string $expected
  817. * @param null|string $input
  818. *
  819. * @dataProvider provideSwitchCases
  820. */
  821. public function testInSwitchStatement(array $config, $expected, $input = null)
  822. {
  823. $this->fixer->configure(['tokens' => $config]);
  824. $this->doTest($expected, $input);
  825. }
  826. public function provideSwitchCases()
  827. {
  828. return [
  829. [
  830. [
  831. 'break',
  832. 'continue',
  833. 'extra',
  834. 'return',
  835. 'throw',
  836. ],
  837. '<?php
  838. /** a */
  839. switch ($a) {
  840. case 1:
  841. break;
  842. case 2:
  843. continue;
  844. case 3:
  845. return 1;
  846. case 4:
  847. throw $e;
  848. case 5:
  849. throw new \Exception();
  850. case Token::STRING_TYPE:
  851. echo 123;
  852. return new ConstantNode($token->getValue());
  853. case 7:
  854. return new ConstantNode($token->getValue());
  855. case 8:
  856. return 8;
  857. default:
  858. echo 1;
  859. }',
  860. '<?php
  861. /** a */
  862. switch ($a) {
  863. case 1:
  864. break;
  865. case 2:
  866. continue;
  867. case 3:
  868. return 1;
  869. case 4:
  870. throw $e;
  871. case 5:
  872. throw new \Exception();
  873. case Token::STRING_TYPE:
  874. echo 123;
  875. return new ConstantNode($token->getValue());
  876. case 7:
  877. return new ConstantNode($token->getValue());
  878. '.'
  879. case 8:
  880. return 8;
  881. '.'
  882. default:
  883. echo 1;
  884. }',
  885. ],
  886. [
  887. [
  888. 'switch',
  889. 'case',
  890. 'default',
  891. ],
  892. '<?php
  893. switch($a) {
  894. case 0:
  895. case 1:
  896. default:
  897. return 1;
  898. }',
  899. '<?php
  900. switch($a) {
  901. case 0:
  902. case 1:
  903. default:
  904. return 1;
  905. }',
  906. ],
  907. [
  908. [
  909. 'switch',
  910. 'case',
  911. 'default',
  912. ],
  913. '<?php
  914. switch($a) { case 2: echo 3;
  915. default: return 1;}
  916. // above stays empty',
  917. '<?php
  918. switch($a) { case 2: echo 3;
  919. default: return 1;}
  920. // above stays empty',
  921. ],
  922. ];
  923. }
  924. public function testRemovingEmptyLinesAfterOpenTag()
  925. {
  926. $this->doTest(
  927. '<?php
  928. class Foo {}',
  929. '<?php
  930. class Foo {}'
  931. );
  932. }
  933. /**
  934. * @param string $expected
  935. * @param null|string $input
  936. *
  937. * @dataProvider provideFix72Cases
  938. * @requires PHP 7.2
  939. */
  940. public function testFix72($expected, $input = null)
  941. {
  942. $this->fixer->configure(['tokens' => ['use']]);
  943. $this->doTest($expected, $input);
  944. }
  945. public function provideFix72Cases()
  946. {
  947. yield [
  948. '<?php
  949. use function A; use function B;
  950. echo 1;',
  951. ];
  952. yield [
  953. '<?php
  954. use some\a\{ClassA, ClassB, ClassC as C,};
  955. use function some\a\{fn_a, fn_b, fn_c,};
  956. use const some\a\{ConstA,ConstB,ConstC
  957. ,
  958. };
  959. use const some\Z\{ConstX,ConstY,ConstZ,};
  960. ',
  961. '<?php
  962. use some\a\{ClassA, ClassB, ClassC as C,};
  963. use function some\a\{fn_a, fn_b, fn_c,};
  964. use const some\a\{ConstA,ConstB,ConstC
  965. ,
  966. };
  967. '.'
  968. use const some\Z\{ConstX,ConstY,ConstZ,};
  969. ',
  970. ];
  971. }
  972. /**
  973. * @param string $expected
  974. *
  975. * @dataProvider provideFix80Cases
  976. * @requires PHP 8.0
  977. */
  978. public function testFix80($expected)
  979. {
  980. $this->fixer->configure(['tokens' => ['throw']]);
  981. $this->doTest($expected);
  982. }
  983. public function provideFix80Cases()
  984. {
  985. yield [
  986. '<?php
  987. $a = $bar ?? throw new \Exception();
  988. $a = $bar ?? throw new \Exception();
  989. $a = $bar ?? throw new \Exception();
  990. ',
  991. ];
  992. yield [
  993. '<?php
  994. $a = $bar ?? throw new \Exception();
  995. // Now, we gonna use it!
  996. var_dump($a);
  997. ',
  998. ];
  999. }
  1000. private function removeLinesFromString($input, array $lineNumbers)
  1001. {
  1002. sort($lineNumbers);
  1003. $lines = explode("\n", $input);
  1004. foreach ($lineNumbers as $lineNumber) {
  1005. --$lineNumber;
  1006. unset($lines[$lineNumber]);
  1007. }
  1008. return implode("\n", $lines);
  1009. }
  1010. }