PhpdocTypesFixerTest.php 7.9 KB

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