PhpdocTypesFixerTest.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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\Phpdoc;
  13. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  14. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  15. /**
  16. * @author Graham Campbell <hello@gjcampbell.co.uk>
  17. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  18. *
  19. * @internal
  20. *
  21. * @covers \PhpCsFixer\AbstractPhpdocTypesFixer
  22. * @covers \PhpCsFixer\Fixer\Phpdoc\PhpdocTypesFixer
  23. */
  24. final class PhpdocTypesFixerTest extends AbstractFixerTestCase
  25. {
  26. /**
  27. * @dataProvider provideFixCases
  28. *
  29. * @param array<string, mixed> $configuration
  30. */
  31. public function testFix(string $expected, ?string $input = null, array $configuration = []): void
  32. {
  33. $this->fixer->configure($configuration);
  34. $this->doTest($expected, $input);
  35. }
  36. public static function provideFixCases(): iterable
  37. {
  38. yield 'windows line breaks' => [
  39. "<?php /**\r\n * @param string|string[] \$bar\r\n *\r\n * @return int[]\r\n */\r\n",
  40. "<?php /**\r\n * @param STRING|String[] \$bar\r\n *\r\n * @return inT[]\r\n */\r\n",
  41. ];
  42. yield 'conversion' => [
  43. '<?php
  44. /**
  45. * @param boolean|array|Foo $bar
  46. *
  47. * @return int|float
  48. */
  49. ',
  50. '<?php
  51. /**
  52. * @param Boolean|Array|Foo $bar
  53. *
  54. * @return inT|Float
  55. */
  56. ',
  57. ];
  58. yield 'array stuff' => [
  59. '<?php
  60. /**
  61. * @param string|string[] $bar
  62. *
  63. * @return int[]
  64. */
  65. ',
  66. '<?php
  67. /**
  68. * @param STRING|String[] $bar
  69. *
  70. * @return inT[]
  71. */
  72. ',
  73. ];
  74. yield 'nested array stuff' => [
  75. '<?php
  76. /**
  77. * @return int[][][]
  78. */
  79. ',
  80. '<?php
  81. /**
  82. * @return INT[][][]
  83. */
  84. ',
  85. ];
  86. yield 'mixed and void' => [
  87. '<?php
  88. /**
  89. * @param mixed $foo
  90. *
  91. * @return void
  92. */
  93. ',
  94. '<?php
  95. /**
  96. * @param Mixed $foo
  97. *
  98. * @return Void
  99. */
  100. ',
  101. ];
  102. yield 'iterable' => [
  103. '<?php
  104. /**
  105. * @param iterable $foo
  106. *
  107. * @return Itter
  108. */
  109. ',
  110. '<?php
  111. /**
  112. * @param Iterable $foo
  113. *
  114. * @return Itter
  115. */
  116. ',
  117. ];
  118. yield 'method and property' => [
  119. '<?php
  120. /**
  121. * @method self foo()
  122. * @property int $foo
  123. * @property-read boolean $bar
  124. * @property-write mixed $baz
  125. */
  126. ',
  127. '<?php
  128. /**
  129. * @method Self foo()
  130. * @property Int $foo
  131. * @property-read Boolean $bar
  132. * @property-write MIXED $baz
  133. */
  134. ',
  135. ];
  136. yield 'throws' => [
  137. '<?php
  138. /**
  139. * @throws static
  140. */
  141. ',
  142. '<?php
  143. /**
  144. * @throws STATIC
  145. */
  146. ',
  147. ];
  148. yield 'inline doc' => [
  149. '<?php
  150. /**
  151. * Does stuff with stuffs.
  152. *
  153. * @param array $stuffs {
  154. * @var bool $foo
  155. * @var int $bar
  156. * }
  157. */
  158. ',
  159. '<?php
  160. /**
  161. * Does stuff with stuffs.
  162. *
  163. * @param array $stuffs {
  164. * @var Bool $foo
  165. * @var INT $bar
  166. * }
  167. */
  168. ',
  169. ];
  170. yield 'with config' => [
  171. '<?php
  172. /**
  173. * @param self|array|Foo $bar
  174. *
  175. * @return int|float|boolean|Double
  176. */
  177. ',
  178. '<?php
  179. /**
  180. * @param SELF|Array|Foo $bar
  181. *
  182. * @return inT|Float|boolean|Double
  183. */
  184. ',
  185. ['groups' => ['simple', 'meta']],
  186. ];
  187. yield 'generics' => [
  188. '<?php
  189. /**
  190. * @param array<int, object> $a
  191. * @param array<iterable> $b
  192. * @param array<parent|$this|self> $c
  193. * @param iterable<Foo\Int\Bar|Foo\Int|Int\Bar> $thisShouldNotBeChanged
  194. * @param iterable<BOOLBOOLBOOL|INTINTINT|ARRAY_BOOL_INT_STRING_> $thisShouldNotBeChangedNeither
  195. *
  196. * @return array<int, array<string, array<int, DoNotChangeThisAsThisIsAClass>>>
  197. */',
  198. '<?php
  199. /**
  200. * @param ARRAY<INT, OBJECT> $a
  201. * @param ARRAY<ITERABLE> $b
  202. * @param array<Parent|$This|Self> $c
  203. * @param iterable<Foo\Int\Bar|Foo\Int|Int\Bar> $thisShouldNotBeChanged
  204. * @param iterable<BOOLBOOLBOOL|INTINTINT|ARRAY_BOOL_INT_STRING_> $thisShouldNotBeChangedNeither
  205. *
  206. * @return ARRAY<INT, ARRAY<STRING, ARRAY<INT, DoNotChangeThisAsThisIsAClass>>>
  207. */',
  208. ['groups' => ['simple', 'meta']],
  209. ];
  210. yield 'callable' => [
  211. '<?php /**
  212. * @param callable() $a
  213. * @param callable(): void $b
  214. * @param callable(bool, int, string): float $c
  215. */',
  216. '<?php /**
  217. * @param CALLABLE() $a
  218. * @param Callable(): VOID $b
  219. * @param CALLABLE(BOOL, INT, STRING): FLOAT $c
  220. */',
  221. ];
  222. yield 'array shape with key name being also type name' => [
  223. '<?php /**
  224. * @return array{FOO: bool, NULL: null|int, BAR: string|BAZ}
  225. */',
  226. '<?php /**
  227. * @return ARRAY{FOO: BOOL, NULL: NULL|INT, BAR: STRING|BAZ}
  228. */',
  229. ];
  230. yield 'union with \'NULL\'' => [
  231. '<?php /**
  232. * @return \'NULL\'|null|false
  233. */',
  234. '<?php /**
  235. * @return \'NULL\'|NULL|false
  236. */',
  237. ];
  238. yield 'union with "NULL"' => [
  239. '<?php /**
  240. * @return null|"NULL"|false
  241. */',
  242. '<?php /**
  243. * @return NULL|"NULL"|false
  244. */',
  245. ];
  246. yield 'method with reserved identifier' => [
  247. '<?php /**
  248. * @method bool BOOL(): void
  249. */',
  250. '<?php /**
  251. * @method BOOL BOOL(): void
  252. */',
  253. ];
  254. yield 'no space between type and variable' => [
  255. '<?php /** @param null|string$foo */',
  256. '<?php /** @param NULL|STRING$foo */',
  257. ];
  258. yield '"Callback" class in phpdoc must not be lowered' => [
  259. '<?php
  260. /**
  261. * @param Callback $foo
  262. *
  263. * @return Callback
  264. */
  265. ',
  266. ];
  267. yield 'param with extra chevrons' => [
  268. '<?php /** @param array <3> $value */',
  269. '<?php /** @param ARRAY <3> $value */',
  270. ];
  271. yield 'param with extra parentheses' => [
  272. '<?php /** @param \Closure (int) $value */',
  273. '<?php /** @param \Closure (INT) $value */',
  274. ];
  275. yield 'param with union type and extra parentheses' => [
  276. '<?php /** @param \Closure (float|int) $value */',
  277. '<?php /** @param \Closure (FLOAT|INT) $value */',
  278. ];
  279. yield 'return with union type and extra parentheses' => [
  280. '<?php /** @return float|int (number) count of something */',
  281. '<?php /** @return FLOAT|INT (number) count of something */',
  282. ];
  283. }
  284. public function testWrongConfig(): void
  285. {
  286. $this->expectException(InvalidFixerConfigurationException::class);
  287. $this->expectExceptionMessageMatches('/^\[phpdoc_types\] Invalid configuration: The option "groups" .*\.$/');
  288. $this->fixer->configure(['groups' => ['__TEST__']]);
  289. }
  290. }