PsrAutoloadingFixerTest.php 14 KB

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