AbstractProxyFixerTest.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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\AbstractProxyFixer;
  14. use PhpCsFixer\AccessibleObject\AccessibleObject;
  15. use PhpCsFixer\Fixer\FixerInterface;
  16. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  17. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  18. use PhpCsFixer\Tokenizer\Tokens;
  19. use PhpCsFixer\WhitespacesFixerConfig;
  20. /**
  21. * @internal
  22. *
  23. * @covers \PhpCsFixer\AbstractProxyFixer
  24. */
  25. final class AbstractProxyFixerTest extends TestCase
  26. {
  27. public function testCandidate(): void
  28. {
  29. $proxyFixer = $this->createProxyFixerDouble([$this->createFixerDouble(true)]);
  30. self::assertTrue($proxyFixer->isCandidate(new Tokens()));
  31. $proxyFixer = $this->createProxyFixerDouble([$this->createFixerDouble(false)]);
  32. self::assertFalse($proxyFixer->isCandidate(new Tokens()));
  33. $proxyFixer = $this->createProxyFixerDouble([
  34. $this->createFixerDouble(false),
  35. $this->createFixerDouble(true),
  36. ]);
  37. self::assertTrue($proxyFixer->isCandidate(new Tokens()));
  38. }
  39. public function testRisky(): void
  40. {
  41. $proxyFixer = $this->createProxyFixerDouble([$this->createFixerDouble(true, false)]);
  42. self::assertFalse($proxyFixer->isRisky());
  43. $proxyFixer = $this->createProxyFixerDouble([$this->createFixerDouble(true, true)]);
  44. self::assertTrue($proxyFixer->isRisky());
  45. $proxyFixer = $this->createProxyFixerDouble([
  46. $this->createFixerDouble(true, false),
  47. $this->createFixerDouble(true, true),
  48. $this->createFixerDouble(true, false),
  49. ]);
  50. self::assertTrue($proxyFixer->isRisky());
  51. }
  52. public function testSupports(): void
  53. {
  54. $file = new \SplFileInfo(__FILE__);
  55. $proxyFixer = $this->createProxyFixerDouble([$this->createFixerDouble(true, false, false)]);
  56. self::assertFalse($proxyFixer->supports($file));
  57. $proxyFixer = $this->createProxyFixerDouble([$this->createFixerDouble(true, true, true)]);
  58. self::assertTrue($proxyFixer->supports($file));
  59. $proxyFixer = $this->createProxyFixerDouble([
  60. $this->createFixerDouble(true, false, false),
  61. $this->createFixerDouble(true, true, false),
  62. $this->createFixerDouble(true, false, true),
  63. ]);
  64. self::assertTrue($proxyFixer->supports($file));
  65. }
  66. public function testPrioritySingleFixer(): void
  67. {
  68. $proxyFixer = $this->createProxyFixerDouble([
  69. $this->createFixerDouble(true, false, false, 123),
  70. ]);
  71. self::assertSame(123, $proxyFixer->getPriority());
  72. }
  73. public function testPriorityMultipleFixersNotSet(): void
  74. {
  75. $proxyFixer = $this->createProxyFixerDouble([
  76. $this->createFixerDouble(true),
  77. $this->createFixerDouble(true, true),
  78. $this->createFixerDouble(true, false, true),
  79. ]);
  80. $this->expectException(\LogicException::class);
  81. $this->expectExceptionMessage('You need to override this method to provide the priority of combined fixers.');
  82. $proxyFixer->getPriority();
  83. }
  84. public function testWhitespacesConfig(): void
  85. {
  86. $config = new WhitespacesFixerConfig();
  87. $whitespacesAwareFixer = $this->createWhitespacesAwareFixerDouble();
  88. $proxyFixer = $this->createProxyFixerDouble([
  89. $this->createFixerDouble(true, true),
  90. $whitespacesAwareFixer,
  91. $this->createFixerDouble(true, false, true),
  92. ]);
  93. $proxyFixer->setWhitespacesConfig($config);
  94. self::assertSame($config, AccessibleObject::create($whitespacesAwareFixer)->whitespacesConfig);
  95. }
  96. public function testApplyFixInPriorityOrder(): void
  97. {
  98. $fixer1 = $this->createFixerDouble(true, false, true, 1);
  99. $fixer2 = $this->createFixerDouble(true, false, true, 10);
  100. $proxyFixer = $this->createProxyFixerDouble([$fixer1, $fixer2]);
  101. $proxyFixer->fix(new \SplFileInfo(__FILE__), Tokens::fromCode('<?php echo 1;'));
  102. self::assertSame(2, AccessibleObject::create($fixer1)->fixCalled);
  103. self::assertSame(1, AccessibleObject::create($fixer2)->fixCalled);
  104. }
  105. private function createFixerDouble(
  106. bool $isCandidate,
  107. bool $isRisky = false,
  108. bool $supports = false,
  109. int $priority = 999
  110. ): FixerInterface {
  111. return new class($isCandidate, $isRisky, $supports, $priority) implements FixerInterface {
  112. private bool $isCandidate;
  113. private bool $isRisky;
  114. private bool $supports;
  115. private int $priority;
  116. private int $fixCalled = 0;
  117. private static int $callCount = 1;
  118. public function __construct(bool $isCandidate, bool $isRisky, bool $supports, int $priority)
  119. {
  120. $this->isCandidate = $isCandidate;
  121. $this->isRisky = $isRisky;
  122. $this->supports = $supports;
  123. $this->priority = $priority;
  124. }
  125. public function fix(\SplFileInfo $file, Tokens $tokens): void
  126. {
  127. if (0 !== $this->fixCalled) {
  128. throw new \RuntimeException('Fixer called multiple times.');
  129. }
  130. $this->fixCalled = self::$callCount;
  131. ++self::$callCount;
  132. }
  133. public function getDefinition(): FixerDefinitionInterface
  134. {
  135. throw new \BadMethodCallException('Not implemented.');
  136. }
  137. public function getName(): string
  138. {
  139. return uniqid('abstract_proxy_test_');
  140. }
  141. public function getPriority(): int
  142. {
  143. return $this->priority;
  144. }
  145. public function isCandidate(Tokens $tokens): bool
  146. {
  147. return $this->isCandidate;
  148. }
  149. public function isRisky(): bool
  150. {
  151. return $this->isRisky;
  152. }
  153. public function supports(\SplFileInfo $file): bool
  154. {
  155. return $this->supports;
  156. }
  157. };
  158. }
  159. private function createWhitespacesAwareFixerDouble(): WhitespacesAwareFixerInterface
  160. {
  161. return new class implements WhitespacesAwareFixerInterface {
  162. /** @phpstan-ignore-next-line to not complain that property is never read */
  163. private WhitespacesFixerConfig $whitespacesConfig;
  164. public function getDefinition(): FixerDefinitionInterface
  165. {
  166. throw new \BadMethodCallException('Not implemented.');
  167. }
  168. public function fix(\SplFileInfo $file, Tokens $tokens): void
  169. {
  170. throw new \BadMethodCallException('Not implemented.');
  171. }
  172. public function getName(): string
  173. {
  174. return uniqid('abstract_proxy_aware_test_');
  175. }
  176. public function getPriority(): int
  177. {
  178. return 1;
  179. }
  180. public function isCandidate(Tokens $tokens): bool
  181. {
  182. throw new \BadMethodCallException('Not implemented.');
  183. }
  184. public function isRisky(): bool
  185. {
  186. throw new \BadMethodCallException('Not implemented.');
  187. }
  188. public function setWhitespacesConfig(WhitespacesFixerConfig $config): void
  189. {
  190. $this->whitespacesConfig = $config;
  191. }
  192. public function supports(\SplFileInfo $file): bool
  193. {
  194. throw new \BadMethodCallException('Not implemented.');
  195. }
  196. };
  197. }
  198. /**
  199. * @param list<FixerInterface> $fixers
  200. */
  201. private function createProxyFixerDouble(array $fixers): AbstractProxyFixer
  202. {
  203. return new class($fixers) extends AbstractProxyFixer implements WhitespacesAwareFixerInterface {
  204. /**
  205. * @var list<FixerInterface>
  206. */
  207. private array $fixers;
  208. /**
  209. * @param list<FixerInterface> $fixers
  210. */
  211. public function __construct(array $fixers)
  212. {
  213. $this->fixers = $fixers;
  214. parent::__construct();
  215. }
  216. public function getDefinition(): FixerDefinitionInterface
  217. {
  218. throw new \BadMethodCallException('Not implemented.');
  219. }
  220. protected function createProxyFixers(): array
  221. {
  222. return $this->fixers;
  223. }
  224. };
  225. }
  226. }