ProtectedToPrivateFixerTest.php 8.8 KB

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