ProtectedToPrivateFixerTest.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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\ClassNotation;
  13. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  14. /**
  15. * @author Filippo Tessarotto <zoeslam@gmail.com>
  16. *
  17. * @internal
  18. *
  19. * @covers \PhpCsFixer\Fixer\ClassNotation\ProtectedToPrivateFixer
  20. *
  21. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\ClassNotation\ProtectedToPrivateFixer>
  22. */
  23. final class ProtectedToPrivateFixerTest extends AbstractFixerTestCase
  24. {
  25. /**
  26. * @dataProvider provideFixCases
  27. */
  28. public function testFix(string $expected, ?string $input = null): void
  29. {
  30. $this->doTest($expected, $input);
  31. }
  32. /**
  33. * @return iterable<int|string, array{0: string, 1?: string}>
  34. */
  35. public static function provideFixCases(): iterable
  36. {
  37. $attributesAndMethodsOriginal = self::getAttributesAndMethods(true);
  38. $attributesAndMethodsFixed = self::getAttributesAndMethods(false);
  39. yield 'final-extends' => [
  40. "<?php final class MyClass extends MyAbstractClass { {$attributesAndMethodsOriginal} }",
  41. ];
  42. yield 'normal-extends' => [
  43. "<?php class MyClass extends MyAbstractClass { {$attributesAndMethodsOriginal} }",
  44. ];
  45. yield 'abstract' => [
  46. "<?php abstract class MyAbstractClass { {$attributesAndMethodsOriginal} }",
  47. ];
  48. yield 'normal' => [
  49. "<?php class MyClass { {$attributesAndMethodsOriginal} }",
  50. ];
  51. yield 'trait' => [
  52. "<?php trait MyTrait { {$attributesAndMethodsOriginal} }",
  53. ];
  54. yield 'final-with-trait' => [
  55. "<?php final class MyClass { use MyTrait; {$attributesAndMethodsOriginal} }",
  56. ];
  57. yield 'multiline-comment' => [
  58. '<?php final class MyClass { /* public protected private */ }',
  59. ];
  60. yield 'inline-comment' => [
  61. "<?php final class MyClass { \n // public protected private \n }",
  62. ];
  63. yield 'final' => [
  64. "<?php final class MyClass { {$attributesAndMethodsFixed} } class B {use C;}",
  65. "<?php final class MyClass { {$attributesAndMethodsOriginal} } class B {use C;}",
  66. ];
  67. yield 'final-implements' => [
  68. "<?php final class MyClass implements MyInterface { {$attributesAndMethodsFixed} }",
  69. "<?php final class MyClass implements MyInterface { {$attributesAndMethodsOriginal} }",
  70. ];
  71. yield 'final-with-use-before' => [
  72. "<?php use stdClass; final class MyClass { {$attributesAndMethodsFixed} }",
  73. "<?php use stdClass; final class MyClass { {$attributesAndMethodsOriginal} }",
  74. ];
  75. yield 'final-with-use-after' => [
  76. "<?php final class MyClass { {$attributesAndMethodsFixed} } use stdClass;",
  77. "<?php final class MyClass { {$attributesAndMethodsOriginal} } use stdClass;",
  78. ];
  79. yield 'multiple-classes' => [
  80. "<?php final class MyFirstClass { {$attributesAndMethodsFixed} } class MySecondClass { {$attributesAndMethodsOriginal} } final class MyThirdClass { {$attributesAndMethodsFixed} } ",
  81. "<?php final class MyFirstClass { {$attributesAndMethodsOriginal} } class MySecondClass { {$attributesAndMethodsOriginal} } final class MyThirdClass { {$attributesAndMethodsOriginal} } ",
  82. ];
  83. yield 'minimal-set' => [
  84. '<?php final class MyClass { private $v1; }',
  85. '<?php final class MyClass { protected $v1; }',
  86. ];
  87. yield 'anonymous-class-inside' => [
  88. "<?php
  89. final class Foo
  90. {
  91. {$attributesAndMethodsFixed}
  92. private function bar()
  93. {
  94. new class {
  95. {$attributesAndMethodsOriginal}
  96. };
  97. }
  98. }
  99. ",
  100. "<?php
  101. final class Foo
  102. {
  103. {$attributesAndMethodsOriginal}
  104. protected function bar()
  105. {
  106. new class {
  107. {$attributesAndMethodsOriginal}
  108. };
  109. }
  110. }
  111. ",
  112. ];
  113. yield [
  114. '<?php $a = new class{protected function A(){ echo 123; }};',
  115. ];
  116. yield [
  117. '<?php final class Foo { private int $foo; }',
  118. '<?php final class Foo { protected int $foo; }',
  119. ];
  120. yield [
  121. '<?php final class Foo { private ?string $foo; }',
  122. '<?php final class Foo { protected ?string $foo; }',
  123. ];
  124. yield [
  125. '<?php final class Foo { private array $foo; }',
  126. '<?php final class Foo { protected array $foo; }',
  127. ];
  128. }
  129. /**
  130. * @dataProvider provideFix80Cases
  131. *
  132. * @requires PHP 8.0
  133. */
  134. public function testFix80(string $expected, ?string $input = null): void
  135. {
  136. $this->doTest($expected, $input);
  137. }
  138. /**
  139. * @return iterable<array{string, string}>
  140. */
  141. public static function provideFix80Cases(): iterable
  142. {
  143. yield [
  144. '<?php
  145. final class Foo2 {
  146. private int|float $a;
  147. }
  148. ',
  149. '<?php
  150. final class Foo2 {
  151. protected int|float $a;
  152. }
  153. ',
  154. ];
  155. }
  156. /**
  157. * @dataProvider provideFix81Cases
  158. *
  159. * @requires PHP 8.1
  160. */
  161. public function testFix81(string $expected, ?string $input = null): void
  162. {
  163. $this->doTest($expected, $input);
  164. }
  165. /**
  166. * @return iterable<int|string, array{0: string, 1?: string}>
  167. */
  168. public static function provideFix81Cases(): iterable
  169. {
  170. yield [
  171. '<?php
  172. final class Foo { private readonly int $d; }
  173. ',
  174. '<?php
  175. final class Foo { protected readonly int $d; }
  176. ',
  177. ];
  178. yield 'protected final const' => [
  179. // '<?php final class Foo { final private const Y = "i"; }', 'Fatal error: Private constant Foo::Y cannot be final as it is not visible to other classes on line 1.
  180. '<?php
  181. final class Foo1 { final protected const Y = "abc"; }
  182. final class Foo2 { protected final const Y = "def"; }
  183. ',
  184. ];
  185. yield [
  186. '<?php final class Foo2 { private const X = "tty"; }',
  187. '<?php final class Foo2 { protected const X = "tty"; }',
  188. ];
  189. yield [
  190. '<?php final class Foo { private Foo1&Bar $foo; }',
  191. '<?php final class Foo { protected Foo1&Bar $foo; }',
  192. ];
  193. // https://wiki.php.net/rfc/enumerations
  194. // Methods may be public, private, or protected, although in practice private and protected are equivalent as inheritance is not allowed.
  195. yield 'enum' => [
  196. '<?php
  197. enum Foo: string
  198. {
  199. private const Spades = 123;
  200. case Hearts = "H";
  201. private function test() {
  202. echo 123;
  203. }
  204. }
  205. Foo::Hearts->test();
  206. ',
  207. '<?php
  208. enum Foo: string
  209. {
  210. protected const Spades = 123;
  211. case Hearts = "H";
  212. protected function test() {
  213. echo 123;
  214. }
  215. }
  216. Foo::Hearts->test();
  217. ',
  218. ];
  219. yield 'enum with trait' => [
  220. '<?php
  221. trait NamedDocumentStatus
  222. {
  223. public function getStatusName(): string
  224. {
  225. return $this->getFoo();
  226. }
  227. }
  228. enum DocumentStats {
  229. use NamedDocumentStatus;
  230. case DRAFT;
  231. private function getFoo(): string {
  232. return "X";
  233. }
  234. }
  235. echo DocumentStats::DRAFT->getStatusName();
  236. ',
  237. '<?php
  238. trait NamedDocumentStatus
  239. {
  240. public function getStatusName(): string
  241. {
  242. return $this->getFoo();
  243. }
  244. }
  245. enum DocumentStats {
  246. use NamedDocumentStatus;
  247. case DRAFT;
  248. protected function getFoo(): string {
  249. return "X";
  250. }
  251. }
  252. echo DocumentStats::DRAFT->getStatusName();
  253. ',
  254. ];
  255. }
  256. /**
  257. * @dataProvider provideFix82Cases
  258. *
  259. * @requires PHP 8.2
  260. */
  261. public function testFix82(string $expected, string $input): void
  262. {
  263. $this->doTest($expected, $input);
  264. }
  265. /**
  266. * @return iterable<string, array{string, string}>
  267. */
  268. public static function provideFix82Cases(): iterable
  269. {
  270. yield 'final readonly' => [
  271. '<?php
  272. final readonly class Foo {
  273. private function noop(): void{}
  274. }',
  275. '<?php
  276. final readonly class Foo {
  277. protected function noop(): void{}
  278. }',
  279. ];
  280. yield 'final readonly reversed' => [
  281. '<?php
  282. readonly final class Foo {
  283. private function noop(): void{}
  284. }',
  285. '<?php
  286. readonly final class Foo {
  287. protected function noop(): void{}
  288. }',
  289. ];
  290. }
  291. private static function getAttributesAndMethods(bool $original): string
  292. {
  293. $attributesAndMethodsOriginal = '
  294. public $v1;
  295. protected $v2;
  296. private $v3;
  297. public static $v4;
  298. protected static $v5;
  299. private static $v6;
  300. public function f1(){}
  301. protected function f2(){}
  302. private function f3(){}
  303. public static function f4(){}
  304. protected static function f5(){}
  305. private static function f6(){}
  306. ';
  307. if ($original) {
  308. return $attributesAndMethodsOriginal;
  309. }
  310. return str_replace('protected', 'private', $attributesAndMethodsOriginal);
  311. }
  312. }