AttributeTransformerTest.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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\Tokenizer\Transformer;
  13. use PhpCsFixer\Tests\Test\AbstractTransformerTestCase;
  14. use PhpCsFixer\Tokenizer\CT;
  15. use PhpCsFixer\Tokenizer\Tokens;
  16. /**
  17. * @internal
  18. *
  19. * @covers \PhpCsFixer\Tokenizer\Transformer\AttributeTransformer
  20. */
  21. final class AttributeTransformerTest extends AbstractTransformerTestCase
  22. {
  23. /**
  24. * @param array<int, int> $expectedTokens
  25. *
  26. * @dataProvider provideProcessCases
  27. *
  28. * @requires PHP 8.0
  29. */
  30. public function testProcess(string $source, array $expectedTokens): void
  31. {
  32. $this->doTest($source, $expectedTokens);
  33. }
  34. public static function provideProcessCases(): iterable
  35. {
  36. yield ['<?php class Foo {
  37. #[Listens(ProductCreatedEvent::class)]
  38. public $foo;
  39. }
  40. ',
  41. [
  42. 14 => CT::T_ATTRIBUTE_CLOSE,
  43. ],
  44. ];
  45. yield ['<?php class Foo {
  46. #[Required]
  47. public $bar;
  48. }',
  49. [
  50. 9 => CT::T_ATTRIBUTE_CLOSE,
  51. ],
  52. ];
  53. yield [
  54. '<?php function foo(
  55. #[MyAttr([1, 2])] Type $myParam,
  56. ) {}',
  57. [
  58. 16 => CT::T_ATTRIBUTE_CLOSE,
  59. ],
  60. ];
  61. yield [
  62. '<?php class Foo {
  63. #[ORM\Column("string", ORM\Column::UNIQUE)]
  64. #[Assert\Email(["message" => "The email {{ value }} is not a valid email."])]
  65. private $email;
  66. }',
  67. [
  68. 21 => CT::T_ATTRIBUTE_CLOSE,
  69. 36 => CT::T_ATTRIBUTE_CLOSE,
  70. ],
  71. ];
  72. yield [
  73. '<?php
  74. #[ORM\Id]
  75. #[ConditionalDeclare(PHP_VERSION_ID < 70000+1**2-1>>9+foo(a)+foo((bool)$b))] // gets removed from AST when >= 7.0
  76. #[IgnoreRedeclaration] // throws no error when already declared, removes the redeclared thing
  77. function intdiv(int $numerator, int $divisor) {
  78. }
  79. #[
  80. Attr1("foo"),Attr2("bar"),
  81. ]
  82. #[PhpAttribute(self::IS_REPEATABLE)]
  83. class Route
  84. {
  85. }
  86. ',
  87. [
  88. 5 => CT::T_ATTRIBUTE_CLOSE,
  89. 35 => CT::T_ATTRIBUTE_CLOSE,
  90. 41 => CT::T_ATTRIBUTE_CLOSE,
  91. 76 => CT::T_ATTRIBUTE_CLOSE,
  92. 85 => CT::T_ATTRIBUTE_CLOSE,
  93. ],
  94. ];
  95. yield [
  96. '<?php
  97. #[Jit]
  98. function foo() {}
  99. class Foo
  100. {
  101. #[ExampleAttribute]
  102. public const FOO = "foo";
  103. #[ExampleAttribute]
  104. public function foo(#[ExampleAttribute] Type $bar) {}
  105. }
  106. $object = new #[ExampleAttribute] class () {};
  107. $f1 = #[ExampleAttribute] function () {};
  108. $f2 = #[ExampleAttribute] fn() => 1;
  109. ',
  110. [
  111. 3 => CT::T_ATTRIBUTE_CLOSE,
  112. 22 => CT::T_ATTRIBUTE_CLOSE,
  113. 37 => CT::T_ATTRIBUTE_CLOSE,
  114. 47 => CT::T_ATTRIBUTE_CLOSE,
  115. 67 => CT::T_ATTRIBUTE_CLOSE,
  116. 84 => CT::T_ATTRIBUTE_CLOSE,
  117. 101 => CT::T_ATTRIBUTE_CLOSE,
  118. ],
  119. ];
  120. yield [
  121. '<?php
  122. #[
  123. ORM\Entity,
  124. ORM\Table("user")
  125. ]
  126. class User
  127. {
  128. #[ORM\Id, ORM\Column("integer"), ORM\GeneratedValue]
  129. private $id;
  130. #[ORM\Column("string", ORM\Column::UNIQUE)]
  131. #[Assert\Email(["message" => "The email \'{{ value }}\' is not a valid email."])]
  132. private $email;
  133. #[\Doctrine\ORM\ManyToMany(
  134. targetEntity: User::class,
  135. joinColumn: "group_id",
  136. inverseJoinColumn: "user_id",
  137. cascade: array("persist", "remove")
  138. )]
  139. #[Assert\Valid]
  140. #[JMSSerializer\XmlList(inline: true, entry: "user")]
  141. public $users;
  142. }
  143. ',
  144. [
  145. 15 => CT::T_ATTRIBUTE_CLOSE,
  146. 40 => CT::T_ATTRIBUTE_CLOSE,
  147. 61 => CT::T_ATTRIBUTE_CLOSE,
  148. 76 => CT::T_ATTRIBUTE_CLOSE,
  149. 124 => CT::T_ATTRIBUTE_CLOSE,
  150. 130 => CT::T_ATTRIBUTE_CLOSE,
  151. 148 => CT::T_ATTRIBUTE_CLOSE,
  152. ],
  153. ];
  154. }
  155. /**
  156. * @dataProvider provideNotChangeCases
  157. */
  158. public function testNotChange(string $source): void
  159. {
  160. Tokens::clearCache();
  161. foreach (Tokens::fromCode($source) as $token) {
  162. self::assertFalse($token->isGivenKind([
  163. CT::T_ATTRIBUTE_CLOSE,
  164. ]));
  165. }
  166. }
  167. public static function provideNotChangeCases(): iterable
  168. {
  169. yield [
  170. '<?php
  171. $foo = [];
  172. $a[] = $b[1];
  173. $c = $d[2];
  174. // [$e] = $f;',
  175. ];
  176. yield [
  177. '<?php [$e] = $f;',
  178. ];
  179. }
  180. }