PsrAutoloadingFixerTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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\Basic;
  13. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  14. use Prophecy\Prophet;
  15. /**
  16. * @author Graham Campbell <hello@gjcampbell.co.uk>
  17. * @author Kuba Werłos <werlos@gmail.com>
  18. *
  19. * @internal
  20. *
  21. * @covers \PhpCsFixer\Fixer\Basic\PsrAutoloadingFixer
  22. */
  23. final class PsrAutoloadingFixerTest extends AbstractFixerTestCase
  24. {
  25. /**
  26. * This is new test method, to replace old one some day.
  27. *
  28. * @dataProvider provideFixNewCases
  29. */
  30. public function testFixNew(string $expected, ?string $input = null, ?string $dir = null): void
  31. {
  32. if (null !== $dir) {
  33. $this->fixer->configure(['dir' => $dir]);
  34. }
  35. $this->doTest($expected, $input, self::getTestFile(__FILE__));
  36. }
  37. public static function provideFixNewCases(): iterable
  38. {
  39. foreach (['class', 'interface', 'trait'] as $element) {
  40. yield sprintf('%s with originally short name', $element) => [
  41. sprintf('<?php %s PsrAutoloadingFixerTest {}', $element),
  42. sprintf('<?php %s Foo {}', $element),
  43. ];
  44. }
  45. yield 'abstract class' => [
  46. '<?php abstract class PsrAutoloadingFixerTest {}',
  47. '<?php abstract class WrongName {}',
  48. ];
  49. yield 'final class' => [
  50. '<?php final class PsrAutoloadingFixerTest {}',
  51. '<?php final class WrongName {}',
  52. ];
  53. yield 'class with originally long name' => [
  54. '<?php class PsrAutoloadingFixerTest {}',
  55. '<?php class FooFooFooFooFooFooFooFooFooFooFooFooFoo {}',
  56. ];
  57. yield 'class with wrong casing' => [
  58. '<?php class PsrAutoloadingFixerTest {}',
  59. '<?php class psrautoloadingfixertest {}',
  60. ];
  61. yield 'namespaced class with wrong casing' => [
  62. '<?php namespace Foo; class PsrAutoloadingFixerTest {}',
  63. '<?php namespace Foo; class psrautoloadingfixertest {}',
  64. ];
  65. yield 'class with wrong casing (1 level namespace)' => [
  66. '<?php class Basic_PsrAutoloadingFixerTest {}',
  67. '<?php class BASIC_PSRAUTOLOADINGFIXERTEST {}',
  68. ];
  69. yield 'class with wrong casing (2 levels namespace)' => [
  70. '<?php class Fixer_Basic_PsrAutoloadingFixerTest {}',
  71. '<?php class FIXER_BASIC_PSRAUTOLOADINGFIXERTEST {}',
  72. ];
  73. yield 'class with name not matching directory structure' => [
  74. '<?php class PsrAutoloadingFixerTest {}',
  75. '<?php class Aaaaa_Bbbbb_PsrAutoloadingFixerTest {}',
  76. ];
  77. yield 'configured directory (1 subdirectory)' => [
  78. '<?php class Basic_PsrAutoloadingFixerTest {}',
  79. '<?php class PsrAutoloadingFixerTest {}',
  80. __DIR__.'/..',
  81. ];
  82. yield 'configured directory (2 subdirectories)' => [
  83. '<?php class Fixer_Basic_PsrAutoloadingFixerTest {}',
  84. '<?php class PsrAutoloadingFixerTest {}',
  85. __DIR__.'/../..',
  86. ];
  87. yield 'configured directory (other directory)' => [
  88. '<?php namespace Basic; class Foobar {}',
  89. null,
  90. __DIR__.'/../../Test',
  91. ];
  92. yield 'multiple classy elements in file' => [
  93. '<?php interface Foo {} class Bar {}',
  94. ];
  95. yield 'namespace with wrong casing' => [
  96. '<?php namespace Fixer\\Basic; class PsrAutoloadingFixerTest {}',
  97. '<?php namespace Fixer\\BASIC; class PsrAutoloadingFixerTest {}',
  98. __DIR__.'/../..',
  99. ];
  100. yield 'multiple namespaces in file' => [
  101. '<?php namespace Foo\\Helpers; function helper() {}; namespace Foo\\Domain; class Feature {}',
  102. ];
  103. yield 'namespace and class with comments' => [
  104. '<?php namespace /* namespace here */ PhpCsFixer\\Tests\\Fixer\\Basic; class /* hi there */ PsrAutoloadingFixerTest /* hello */ {} /* class end */',
  105. '<?php namespace /* namespace here */ PhpCsFixer\\Tests\\Fixer\\Basic; class /* hi there */ Foo /* hello */ {} /* class end */',
  106. ];
  107. yield 'namespace partially matching directory structure' => [
  108. '<?php namespace Foo\\Bar\\Baz\\FIXER\\Basic; class PsrAutoloadingFixerTest {}',
  109. ];
  110. yield 'namespace partially matching directory structure with comment' => [
  111. '<?php namespace /* hi there */ Foo\\Bar\\Baz\\FIXER\\Basic; class /* hi there */ PsrAutoloadingFixerTest {}',
  112. ];
  113. yield 'namespace partially matching directory structure with configured directory' => [
  114. '<?php namespace Foo\\Bar\\Baz\\Fixer\\Basic; class PsrAutoloadingFixerTest {}',
  115. '<?php namespace Foo\\Bar\\Baz\\FIXER\\Basic; class PsrAutoloadingFixerTest {}',
  116. __DIR__.'/../..',
  117. ];
  118. yield 'namespace partially matching directory structure with comment and configured directory' => [
  119. '<?php namespace /* hi there */ Foo\\Bar\\Baz\\Fixer\\Basic; class /* hi there */ PsrAutoloadingFixerTest {}',
  120. '<?php namespace /* hi there */ Foo\\Bar\\Baz\\FIXER\\Basic; class /* hi there */ PsrAutoloadingFixerTest {}',
  121. __DIR__.'/../..',
  122. ];
  123. yield 'namespace not matching directory structure' => [
  124. '<?php namespace Foo\\Bar\\Baz; class PsrAutoloadingFixerTest {}',
  125. ];
  126. yield 'namespace not matching directory structure with configured directory' => [
  127. '<?php namespace Foo\\Bar\\Baz; class PsrAutoloadingFixerTest {}',
  128. null,
  129. __DIR__,
  130. ];
  131. }
  132. /**
  133. * @dataProvider provideFixCases
  134. * @dataProvider provideIgnoredCases
  135. * @dataProvider provideAnonymousClassCases
  136. */
  137. public function testFix(string $expected, ?string $input = null, ?\SplFileInfo $file = null, ?string $dir = null): void
  138. {
  139. if (null === $file) {
  140. $file = self::getTestFile(__FILE__);
  141. }
  142. if (null !== $dir) {
  143. $this->fixer->configure(['dir' => $dir]);
  144. }
  145. $this->doTest($expected, $input, $file);
  146. }
  147. public static function provideFixCases(): iterable
  148. {
  149. $prophet = new Prophet();
  150. $fileProphecy = $prophet->prophesize(\SplFileInfo::class);
  151. $fileProphecy->willBeConstructedWith(['']);
  152. $fileProphecy->getBasename('.php')->willReturn('Bar');
  153. $fileProphecy->getExtension()->willReturn('php');
  154. $fileProphecy->getRealPath()->willReturn(__DIR__.\DIRECTORY_SEPARATOR.'Psr'.\DIRECTORY_SEPARATOR.'Foo'.\DIRECTORY_SEPARATOR.'Bar.php');
  155. $file = $fileProphecy->reveal();
  156. yield [ // namespace with wrong casing
  157. '<?php
  158. namespace Psr\Foo;
  159. class Bar {}
  160. ',
  161. '<?php
  162. namespace Psr\foo;
  163. class bar {}
  164. ',
  165. $file,
  166. __DIR__,
  167. ];
  168. yield [ // class with wrong casing (2 levels namespace)
  169. '<?php
  170. class Psr_Foo_Bar {}
  171. ',
  172. '<?php
  173. class Psr_fOo_bAr {}
  174. ',
  175. $file,
  176. __DIR__,
  177. ];
  178. yield [ // namespaced class with wrong casing
  179. '<?php
  180. namespace Psr\Foo;
  181. class Bar {}
  182. ',
  183. '<?php
  184. namespace Psr\foo;
  185. class bar {}
  186. ',
  187. $file,
  188. __DIR__,
  189. ];
  190. yield [ // multiple classy elements in file
  191. '<?php
  192. namespace PhpCsFixer\Tests\Fixer\Basic;
  193. interface SomeInterfaceToBeUsedInTests {}
  194. class blah {}
  195. /* class foo */',
  196. ];
  197. yield [ // multiple namespaces in file
  198. '<?php
  199. namespace PhpCsFixer\Tests\Fixer\Basic;
  200. interface SomeInterfaceToBeUsedInTests {}
  201. namespace AnotherNamespace;
  202. class blah {}
  203. /* class foo */',
  204. ];
  205. yield [ // fix class
  206. '<?php
  207. namespace PhpCsFixer\Tests\Fixer\Basic;
  208. class PsrAutoloadingFixerTest {}
  209. /* class foo */
  210. ',
  211. '<?php
  212. namespace PhpCsFixer\Tests\Fixer\Basic;
  213. class blah {}
  214. /* class foo */
  215. ',
  216. ];
  217. yield [ // abstract class
  218. '<?php
  219. namespace PhpCsFixer\Tests\Fixer\Basic;
  220. abstract class PsrAutoloadingFixerTest {}
  221. /* class foo */
  222. ',
  223. '<?php
  224. namespace PhpCsFixer\Tests\Fixer\Basic;
  225. abstract class blah {}
  226. /* class foo */
  227. ',
  228. ];
  229. yield [ // final class
  230. '<?php
  231. namespace PhpCsFixer\Tests\Fixer\Basic;
  232. final class PsrAutoloadingFixerTest {}
  233. /* class foo */
  234. ',
  235. '<?php
  236. namespace PhpCsFixer\Tests\Fixer\Basic;
  237. final class blah {}
  238. /* class foo */
  239. ',
  240. ];
  241. yield [ // namespace and class with comments
  242. '<?php
  243. namespace /* namespace here */ PhpCsFixer\Fixer\Psr;
  244. class /* hi there */ PsrAutoloadingFixerTest /* why hello */ {}
  245. /* class foo */
  246. ',
  247. '<?php
  248. namespace /* namespace here */ PhpCsFixer\Fixer\Psr;
  249. class /* hi there */ blah /* why hello */ {}
  250. /* class foo */
  251. ',
  252. ];
  253. yield [ // namespace partially matching directory structure
  254. '<?php
  255. namespace Foo\Bar\Baz\FIXER\Basic;
  256. class PsrAutoloadingFixer {}
  257. ',
  258. null,
  259. self::getTestFile(__DIR__.'/../../../src/Fixer/Basic/PsrAutoloadingFixer.php'),
  260. ];
  261. yield [ // namespace partially matching directory structure with comment
  262. '<?php
  263. namespace /* hi there */ Foo\Bar\Baz\FIXER\Basic;
  264. class /* hi there */ PsrAutoloadingFixer {}
  265. ',
  266. null,
  267. self::getTestFile(__DIR__.'/../../../src/Fixer/Basic/PsrAutoloadingFixer.php'),
  268. ];
  269. yield [ // namespace not matching directory structure
  270. '<?php
  271. namespace Foo\Bar\Baz;
  272. class PsrAutoloadingFixer {}
  273. ',
  274. null,
  275. self::getTestFile(__DIR__.'/../../../src/Fixer/Basic/PsrAutoloadingFixer.php'),
  276. ];
  277. yield [ // namespace partially matching directory structure with configured directory
  278. '<?php
  279. namespace Foo\Bar\Baz\Fixer\Basic;
  280. class PsrAutoloadingFixer {}
  281. ',
  282. '<?php
  283. namespace Foo\Bar\Baz\FIXER\Basic;
  284. class PsrAutoloadingFixer {}
  285. ',
  286. self::getTestFile(__DIR__.'/../../../src/Fixer/Basic/PsrAutoloadingFixer.php'),
  287. __DIR__.'/../../../src/',
  288. ];
  289. yield [ // namespace partially matching directory structure with comment and configured directory
  290. '<?php
  291. namespace /* hi there */ Foo\Bar\Baz\Fixer\Basic;
  292. class /* hi there */ PsrAutoloadingFixer {}
  293. ',
  294. '<?php
  295. namespace /* hi there */ Foo\Bar\Baz\FIXER\Basic;
  296. class /* hi there */ PsrAutoloadingFixer {}
  297. ',
  298. self::getTestFile(__DIR__.'/../../../src/Fixer/Basic/PsrAutoloadingFixer.php'),
  299. __DIR__.'/../../../src/',
  300. ];
  301. yield [ // namespace not matching directory structure with configured directory
  302. '<?php
  303. namespace Foo\Bar\Baz;
  304. class PsrAutoloadingFixer {}
  305. ',
  306. null,
  307. self::getTestFile(__DIR__.'/../../../src/Fixer/Basic/PsrAutoloadingFixer.php'),
  308. __DIR__.'/../../../src/Fixer/Basic',
  309. ];
  310. yield [ // class with originally short name
  311. '<?php class PsrAutoloadingFixerTest {}',
  312. '<?php class Foo {}',
  313. ];
  314. yield [ // class with originally long name
  315. '<?php class PsrAutoloadingFixerTest {}',
  316. '<?php class PsrAutoloadingFixerTestFoo {}',
  317. ];
  318. }
  319. public static function provideIgnoredCases(): iterable
  320. {
  321. $cases = ['.php', 'Foo.class.php', '4Foo.php', '$#.php'];
  322. foreach (['__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'try', 'unset', 'use', 'var', 'while', 'xor'] as $keyword) {
  323. $cases[] = $keyword.'.php';
  324. }
  325. foreach (['__CLASS__', '__DIR__', '__FILE__', '__FUNCTION__', '__LINE__', '__METHOD__', '__NAMESPACE__'] as $magicConstant) {
  326. $cases[] = $magicConstant.'.php';
  327. $cases[] = strtolower($magicConstant).'.php';
  328. }
  329. foreach ([
  330. 'T_CALLABLE' => 'callable',
  331. 'T_FINALLY' => 'finally',
  332. 'T_INSTEADOF' => 'insteadof',
  333. 'T_TRAIT' => 'trait',
  334. 'T_TRAIT_C' => '__TRAIT__',
  335. ] as $tokenType => $tokenValue) {
  336. if (\defined($tokenType)) {
  337. $cases[] = $tokenValue.'.php';
  338. $cases[] = strtolower($tokenValue).'.php';
  339. }
  340. }
  341. return array_map(static fn ($case): array => [
  342. '<?php
  343. namespace Aaa;
  344. class Bar {}',
  345. null,
  346. self::getTestFile($case),
  347. ], $cases);
  348. }
  349. public static function provideAnonymousClassCases(): iterable
  350. {
  351. yield 'class with anonymous class' => [
  352. '<?php
  353. namespace PhpCsFixer\Tests\Fixer\Basic;
  354. class PsrAutoloadingFixerTest {
  355. public function foo() {
  356. return new class() implements FooInterface {};
  357. }
  358. }
  359. ',
  360. '<?php
  361. namespace PhpCsFixer\Tests\Fixer\Basic;
  362. class stdClass {
  363. public function foo() {
  364. return new class() implements FooInterface {};
  365. }
  366. }
  367. ',
  368. ];
  369. yield 'ignore anonymous class implementing interface' => [
  370. '<?php
  371. namespace PhpCsFixer\Tests\Fixer\Basic;
  372. new class implements Countable {};
  373. ',
  374. ];
  375. yield 'ignore anonymous class extending other class' => [
  376. '<?php
  377. namespace PhpCsFixer\Tests\Fixer\Basic;
  378. new class extends stdClass {};
  379. ',
  380. ];
  381. yield 'ignore multiple classy in file with anonymous class between them' => [
  382. '<?php
  383. namespace PhpCsFixer\Tests\Fixer\Basic;
  384. class ClassOne {};
  385. new class extends stdClass {};
  386. class ClassTwo {};
  387. ',
  388. ];
  389. }
  390. /**
  391. * @requires PHP 8.0
  392. *
  393. * @dataProvider provideFix80Cases
  394. */
  395. public function testFix80(string $expected, ?string $input = null): void
  396. {
  397. $this->doTest($expected, $input);
  398. }
  399. public static function provideFix80Cases(): iterable
  400. {
  401. yield 'anonymous + annotation' => [
  402. '<?php
  403. namespace PhpCsFixer\Tests\Fixer\Basic;
  404. new
  405. #[Foo]
  406. class extends stdClass {};
  407. ',
  408. ];
  409. }
  410. /**
  411. * @requires PHP 8.1
  412. *
  413. * @dataProvider provideFix81Cases
  414. */
  415. public function testFix81(string $expected, ?string $input = null): void
  416. {
  417. $this->doTest($expected, $input, self::getTestFile(__FILE__));
  418. }
  419. public static function provideFix81Cases(): iterable
  420. {
  421. yield 'enum with wrong casing' => [
  422. '<?php enum PsrAutoloadingFixerTest {}',
  423. '<?php enum psrautoloadingfixertest {}',
  424. ];
  425. }
  426. }