UtilsTest.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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;
  13. use PhpCsFixer\Fixer\FixerInterface;
  14. use PhpCsFixer\Tokenizer\Token;
  15. use PhpCsFixer\Utils;
  16. use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
  17. /**
  18. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  19. * @author Graham Campbell <hello@gjcampbell.co.uk>
  20. * @author Odín del Río <odin.drp@gmail.com>
  21. *
  22. * @internal
  23. *
  24. * @covers \PhpCsFixer\Utils
  25. */
  26. final class UtilsTest extends TestCase
  27. {
  28. use ExpectDeprecationTrait;
  29. /**
  30. * @var null|false|string
  31. */
  32. private $originalValueOfFutureMode;
  33. protected function setUp(): void
  34. {
  35. $this->originalValueOfFutureMode = getenv('PHP_CS_FIXER_FUTURE_MODE');
  36. }
  37. protected function tearDown(): void
  38. {
  39. putenv("PHP_CS_FIXER_FUTURE_MODE={$this->originalValueOfFutureMode}");
  40. }
  41. /**
  42. * @param string $expected Camel case string
  43. *
  44. * @dataProvider provideCamelCaseToUnderscoreCases
  45. */
  46. public function testCamelCaseToUnderscore(string $expected, string $input = null): void
  47. {
  48. if (null !== $input) {
  49. static::assertSame($expected, Utils::camelCaseToUnderscore($input));
  50. }
  51. static::assertSame($expected, Utils::camelCaseToUnderscore($expected));
  52. }
  53. public static function provideCamelCaseToUnderscoreCases(): array
  54. {
  55. return [
  56. [
  57. 'dollar_close_curly_braces',
  58. 'DollarCloseCurlyBraces',
  59. ],
  60. [
  61. 'utf8_encoder_fixer',
  62. 'utf8EncoderFixer',
  63. ],
  64. [
  65. 'terminated_with_number10',
  66. 'TerminatedWithNumber10',
  67. ],
  68. [
  69. 'utf8_encoder_fixer',
  70. ],
  71. [
  72. 'a',
  73. 'A',
  74. ],
  75. [
  76. 'aa',
  77. 'AA',
  78. ],
  79. [
  80. 'foo',
  81. 'FOO',
  82. ],
  83. [
  84. 'foo_bar_baz',
  85. 'FooBarBAZ',
  86. ],
  87. [
  88. 'foo_bar_baz',
  89. 'FooBARBaz',
  90. ],
  91. [
  92. 'foo_bar_baz',
  93. 'FOOBarBaz',
  94. ],
  95. [
  96. 'mr_t',
  97. 'MrT',
  98. ],
  99. [
  100. 'voyage_éclair',
  101. 'VoyageÉclair',
  102. ],
  103. ];
  104. }
  105. /**
  106. * @param array{int, string}|string $input token prototype
  107. *
  108. * @dataProvider provideCalculateTrailingWhitespaceIndentCases
  109. */
  110. public function testCalculateTrailingWhitespaceIndent(string $spaces, $input): void
  111. {
  112. $token = new Token($input);
  113. static::assertSame($spaces, Utils::calculateTrailingWhitespaceIndent($token));
  114. }
  115. public static function provideCalculateTrailingWhitespaceIndentCases(): array
  116. {
  117. return [
  118. [' ', [T_WHITESPACE, "\n\n "]],
  119. [' ', [T_WHITESPACE, "\r\n\r\r\r "]],
  120. ["\t", [T_WHITESPACE, "\r\n\t"]],
  121. ['', [T_WHITESPACE, "\t\n\r"]],
  122. ['', [T_WHITESPACE, "\n"]],
  123. ['', ''],
  124. ];
  125. }
  126. public function testCalculateTrailingWhitespaceIndentFail(): void
  127. {
  128. $this->expectException(\InvalidArgumentException::class);
  129. $this->expectExceptionMessage('The given token must be whitespace, got "T_STRING".');
  130. $token = new Token([T_STRING, 'foo']);
  131. Utils::calculateTrailingWhitespaceIndent($token);
  132. }
  133. /**
  134. * @param list<mixed> $expected
  135. * @param list<mixed> $elements
  136. *
  137. * @dataProvider provideStableSortCases
  138. */
  139. public function testStableSort(
  140. array $expected,
  141. array $elements,
  142. callable $getComparableValueCallback,
  143. callable $compareValuesCallback
  144. ): void {
  145. static::assertSame(
  146. $expected,
  147. Utils::stableSort($elements, $getComparableValueCallback, $compareValuesCallback)
  148. );
  149. }
  150. public static function provideStableSortCases(): array
  151. {
  152. return [
  153. [
  154. ['a', 'b', 'c', 'd', 'e'],
  155. ['b', 'd', 'e', 'a', 'c'],
  156. static fn ($element) => $element,
  157. 'strcmp',
  158. ],
  159. [
  160. ['b', 'd', 'e', 'a', 'c'],
  161. ['b', 'd', 'e', 'a', 'c'],
  162. static fn (): string => 'foo',
  163. 'strcmp',
  164. ],
  165. [
  166. ['b', 'd', 'e', 'a', 'c'],
  167. ['b', 'd', 'e', 'a', 'c'],
  168. static fn ($element) => $element,
  169. static fn (): int => 0,
  170. ],
  171. [
  172. ['bar1', 'baz1', 'foo1', 'bar2', 'baz2', 'foo2'],
  173. ['foo1', 'foo2', 'bar1', 'bar2', 'baz1', 'baz2'],
  174. static fn ($element) => preg_replace('/([a-z]+)(\d+)/', '$2$1', $element),
  175. 'strcmp',
  176. ],
  177. ];
  178. }
  179. public function testSortFixers(): void
  180. {
  181. $fixers = [
  182. $this->createFixerDouble('f1', 0),
  183. $this->createFixerDouble('f2', -10),
  184. $this->createFixerDouble('f3', 10),
  185. $this->createFixerDouble('f4', -10),
  186. ];
  187. static::assertSame(
  188. [
  189. $fixers[2],
  190. $fixers[0],
  191. $fixers[1],
  192. $fixers[3],
  193. ],
  194. Utils::sortFixers($fixers)
  195. );
  196. }
  197. public function testNaturalLanguageJoinWithBackticksThrowsInvalidArgumentExceptionForEmptyArray(): void
  198. {
  199. $this->expectException(\InvalidArgumentException::class);
  200. Utils::naturalLanguageJoinWithBackticks([]);
  201. }
  202. /**
  203. * @param list<string> $names
  204. *
  205. * @dataProvider provideNaturalLanguageJoinWithBackticksCases
  206. */
  207. public function testNaturalLanguageJoinWithBackticks(string $joined, array $names): void
  208. {
  209. static::assertSame($joined, Utils::naturalLanguageJoinWithBackticks($names));
  210. }
  211. public static function provideNaturalLanguageJoinWithBackticksCases(): array
  212. {
  213. return [
  214. [
  215. '`a`',
  216. ['a'],
  217. ],
  218. [
  219. '`a` and `b`',
  220. ['a', 'b'],
  221. ],
  222. [
  223. '`a`, `b` and `c`',
  224. ['a', 'b', 'c'],
  225. ],
  226. ];
  227. }
  228. /**
  229. * @group legacy
  230. */
  231. public function testTriggerDeprecationWhenFutureModeIsOff(): void
  232. {
  233. putenv('PHP_CS_FIXER_FUTURE_MODE=0');
  234. $message = __METHOD__.'::The message';
  235. $this->expectDeprecation($message);
  236. Utils::triggerDeprecation(new \DomainException($message));
  237. $triggered = Utils::getTriggeredDeprecations();
  238. static::assertContains($message, $triggered);
  239. }
  240. public function testTriggerDeprecationWhenFutureModeIsOn(): void
  241. {
  242. putenv('PHP_CS_FIXER_FUTURE_MODE=1');
  243. $message = __METHOD__.'::The message';
  244. $exception = new \DomainException($message);
  245. $futureModeException = null;
  246. try {
  247. Utils::triggerDeprecation($exception);
  248. } catch (\Exception $futureModeException) {
  249. }
  250. static::assertInstanceOf(\RuntimeException::class, $futureModeException);
  251. static::assertSame($exception, $futureModeException->getPrevious());
  252. $triggered = Utils::getTriggeredDeprecations();
  253. static::assertNotContains($message, $triggered);
  254. }
  255. private function createFixerDouble(string $name, int $priority): FixerInterface
  256. {
  257. $fixer = $this->prophesize(FixerInterface::class);
  258. $fixer->getName()->willReturn($name);
  259. $fixer->getPriority()->willReturn($priority);
  260. return $fixer->reveal();
  261. }
  262. }