RunnerTest.php 9.4 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\Runner;
  13. use PhpCsFixer\AccessibleObject\AccessibleObject;
  14. use PhpCsFixer\Cache\Directory;
  15. use PhpCsFixer\Cache\NullCacheManager;
  16. use PhpCsFixer\Console\Command\FixCommand;
  17. use PhpCsFixer\Differ\DifferInterface;
  18. use PhpCsFixer\Differ\NullDiffer;
  19. use PhpCsFixer\Error\Error;
  20. use PhpCsFixer\Error\ErrorsManager;
  21. use PhpCsFixer\Fixer;
  22. use PhpCsFixer\Linter\Linter;
  23. use PhpCsFixer\Linter\LinterInterface;
  24. use PhpCsFixer\Linter\LintingException;
  25. use PhpCsFixer\Linter\LintingResultInterface;
  26. use PhpCsFixer\Runner\Parallel\ParallelConfig;
  27. use PhpCsFixer\Runner\Runner;
  28. use PhpCsFixer\Tests\TestCase;
  29. use PhpCsFixer\ToolInfo;
  30. use Symfony\Component\Console\Input\ArrayInput;
  31. use Symfony\Component\Finder\Finder;
  32. /**
  33. * @internal
  34. *
  35. * @covers \PhpCsFixer\Runner\Runner
  36. */
  37. final class RunnerTest extends TestCase
  38. {
  39. /**
  40. * @covers \PhpCsFixer\Runner\Runner::fix
  41. * @covers \PhpCsFixer\Runner\Runner::fixFile
  42. */
  43. public function testThatFixSuccessfully(): void
  44. {
  45. $linter = $this->createLinterDouble();
  46. $fixers = [
  47. new Fixer\ClassNotation\VisibilityRequiredFixer(),
  48. new Fixer\Import\NoUnusedImportsFixer(), // will be ignored cause of test keyword in namespace
  49. ];
  50. $expectedChangedInfo = [
  51. 'appliedFixers' => ['visibility_required'],
  52. 'diff' => '',
  53. ];
  54. $path = __DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR.'FixerTest'.\DIRECTORY_SEPARATOR.'fix';
  55. $runner = new Runner(
  56. Finder::create()->in($path),
  57. $fixers,
  58. new NullDiffer(),
  59. null,
  60. new ErrorsManager(),
  61. $linter,
  62. true,
  63. new NullCacheManager(),
  64. new Directory($path),
  65. false
  66. );
  67. $changed = $runner->fix();
  68. self::assertCount(2, $changed);
  69. self::assertSame($expectedChangedInfo, array_pop($changed));
  70. self::assertSame($expectedChangedInfo, array_pop($changed));
  71. $path = __DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR.'FixerTest'.\DIRECTORY_SEPARATOR.'fix';
  72. $runner = new Runner(
  73. Finder::create()->in($path),
  74. $fixers,
  75. new NullDiffer(),
  76. null,
  77. new ErrorsManager(),
  78. $linter,
  79. true,
  80. new NullCacheManager(),
  81. new Directory($path),
  82. true
  83. );
  84. $changed = $runner->fix();
  85. self::assertCount(1, $changed);
  86. self::assertSame($expectedChangedInfo, array_pop($changed));
  87. }
  88. /**
  89. * @covers \PhpCsFixer\Runner\Runner::fix
  90. * @covers \PhpCsFixer\Runner\Runner::fixFile
  91. * @covers \PhpCsFixer\Runner\Runner::fixSequential
  92. */
  93. public function testThatSequentialFixOfInvalidFileReportsToErrorManager(): void
  94. {
  95. $errorsManager = new ErrorsManager();
  96. $path = realpath(__DIR__.\DIRECTORY_SEPARATOR.'..').\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR.'FixerTest'.\DIRECTORY_SEPARATOR.'invalid';
  97. $runner = new Runner(
  98. Finder::create()->in($path),
  99. [
  100. new Fixer\ClassNotation\VisibilityRequiredFixer(),
  101. new Fixer\Import\NoUnusedImportsFixer(), // will be ignored cause of test keyword in namespace
  102. ],
  103. new NullDiffer(),
  104. null,
  105. $errorsManager,
  106. new Linter(),
  107. true,
  108. new NullCacheManager()
  109. );
  110. $changed = $runner->fix();
  111. $pathToInvalidFile = $path.\DIRECTORY_SEPARATOR.'somefile.php';
  112. self::assertCount(0, $changed);
  113. $errors = $errorsManager->getInvalidErrors();
  114. self::assertCount(1, $errors);
  115. $error = $errors[0];
  116. self::assertSame(Error::TYPE_INVALID, $error->getType());
  117. self::assertSame($pathToInvalidFile, $error->getFilePath());
  118. }
  119. /**
  120. * @covers \PhpCsFixer\Runner\Runner::fix
  121. * @covers \PhpCsFixer\Runner\Runner::fixFile
  122. * @covers \PhpCsFixer\Runner\Runner::fixParallel
  123. */
  124. public function testThatParallelFixOfInvalidFileReportsToErrorManager(): void
  125. {
  126. $errorsManager = new ErrorsManager();
  127. $path = realpath(__DIR__.\DIRECTORY_SEPARATOR.'..').\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR.'FixerTest'.\DIRECTORY_SEPARATOR.'invalid';
  128. $runner = new Runner(
  129. Finder::create()->in($path),
  130. [
  131. new Fixer\ClassNotation\VisibilityRequiredFixer(),
  132. new Fixer\Import\NoUnusedImportsFixer(), // will be ignored cause of test keyword in namespace
  133. ],
  134. new NullDiffer(),
  135. null,
  136. $errorsManager,
  137. new Linter(),
  138. true,
  139. new NullCacheManager(),
  140. null,
  141. false,
  142. new ParallelConfig(2, 1, 50),
  143. new ArrayInput([], (new FixCommand(new ToolInfo()))->getDefinition())
  144. );
  145. $changed = $runner->fix();
  146. $pathToInvalidFile = $path.\DIRECTORY_SEPARATOR.'somefile.php';
  147. self::assertCount(0, $changed);
  148. $errors = $errorsManager->getInvalidErrors();
  149. self::assertCount(1, $errors);
  150. $error = $errors[0];
  151. self::assertInstanceOf(LintingException::class, $error->getSource());
  152. self::assertSame(Error::TYPE_INVALID, $error->getType());
  153. self::assertSame($pathToInvalidFile, $error->getFilePath());
  154. }
  155. /**
  156. * @requires OS Darwin|Windows
  157. *
  158. * @TODO v4 do not switch on parallel execution by default while this test is not passing on Linux.
  159. *
  160. * @covers \PhpCsFixer\Runner\Runner::fix
  161. * @covers \PhpCsFixer\Runner\Runner::fixFile
  162. * @covers \PhpCsFixer\Runner\Runner::fixParallel
  163. *
  164. * @dataProvider provideParallelFixStopsOnFirstViolationIfSuchOptionIsEnabledCases
  165. */
  166. public function testParallelFixStopsOnFirstViolationIfSuchOptionIsEnabled(bool $stopOnViolation, int $expectedChanges): void
  167. {
  168. $errorsManager = new ErrorsManager();
  169. $path = realpath(__DIR__.\DIRECTORY_SEPARATOR.'..').\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR.'FixerTest'.\DIRECTORY_SEPARATOR.'fix';
  170. $runner = new Runner(
  171. Finder::create()->in($path),
  172. [
  173. new Fixer\ClassNotation\VisibilityRequiredFixer(),
  174. new Fixer\Import\NoUnusedImportsFixer(), // will be ignored cause of test keyword in namespace
  175. ],
  176. new NullDiffer(),
  177. null,
  178. $errorsManager,
  179. new Linter(),
  180. true,
  181. new NullCacheManager(),
  182. null,
  183. $stopOnViolation,
  184. new ParallelConfig(2, 1, 3),
  185. new ArrayInput([], (new FixCommand(new ToolInfo()))->getDefinition())
  186. );
  187. self::assertCount($expectedChanges, $runner->fix());
  188. }
  189. /**
  190. * @return iterable<array{0: bool, 1: int}>
  191. */
  192. public static function provideParallelFixStopsOnFirstViolationIfSuchOptionIsEnabledCases(): iterable
  193. {
  194. yield 'do NOT stop on violation' => [false, 2];
  195. yield 'stop on violation' => [true, 1];
  196. }
  197. /**
  198. * @covers \PhpCsFixer\Runner\Runner::fix
  199. * @covers \PhpCsFixer\Runner\Runner::fixFile
  200. */
  201. public function testThatDiffedFileIsPassedToDiffer(): void
  202. {
  203. $differ = $this->createDifferDouble();
  204. $path = __DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR.'FixerTest'.\DIRECTORY_SEPARATOR.'fix';
  205. $fixers = [
  206. new Fixer\ClassNotation\VisibilityRequiredFixer(),
  207. ];
  208. $runner = new Runner(
  209. Finder::create()->in($path),
  210. $fixers,
  211. $differ,
  212. null,
  213. new ErrorsManager(),
  214. new Linter(),
  215. true,
  216. new NullCacheManager(),
  217. new Directory($path),
  218. true
  219. );
  220. $runner->fix();
  221. self::assertSame($path, AccessibleObject::create($differ)->passedFile->getPath());
  222. }
  223. private function createDifferDouble(): DifferInterface
  224. {
  225. return new class implements DifferInterface {
  226. public ?\SplFileInfo $passedFile = null;
  227. public function diff(string $old, string $new, ?\SplFileInfo $file = null): string
  228. {
  229. $this->passedFile = $file;
  230. return 'some-diff';
  231. }
  232. };
  233. }
  234. private function createLinterDouble(): LinterInterface
  235. {
  236. return new class implements LinterInterface {
  237. public function isAsync(): bool
  238. {
  239. return false;
  240. }
  241. public function lintFile(string $path): LintingResultInterface
  242. {
  243. return new class implements LintingResultInterface {
  244. public function check(): void {}
  245. };
  246. }
  247. public function lintSource(string $source): LintingResultInterface
  248. {
  249. return new class implements LintingResultInterface {
  250. public function check(): void {}
  251. };
  252. }
  253. };
  254. }
  255. }