FixCommandTest.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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\Console\Command;
  13. use PhpCsFixer\ConfigurationException\InvalidConfigurationException;
  14. use PhpCsFixer\Console\Application;
  15. use PhpCsFixer\Console\Command\FixCommand;
  16. use PhpCsFixer\Tests\TestCase;
  17. use PhpCsFixer\ToolInfo;
  18. use Symfony\Component\Console\Command\Command;
  19. use Symfony\Component\Console\Output\OutputInterface;
  20. use Symfony\Component\Console\Tester\CommandTester;
  21. /**
  22. * @internal
  23. *
  24. * @covers \PhpCsFixer\Console\Command\FixCommand
  25. */
  26. final class FixCommandTest extends TestCase
  27. {
  28. public function testIntersectionPathMode(): void
  29. {
  30. $cmdTester = $this->doTestExecute([
  31. '--path-mode' => 'intersection',
  32. '--show-progress' => 'none',
  33. ]);
  34. self::assertSame(
  35. Command::SUCCESS,
  36. $cmdTester->getStatusCode()
  37. );
  38. }
  39. public function testEmptyRulesValue(): void
  40. {
  41. $this->expectException(
  42. InvalidConfigurationException::class
  43. );
  44. $this->expectExceptionMessageMatches(
  45. '#^Empty rules value is not allowed\.$#'
  46. );
  47. $this->doTestExecute(
  48. ['--rules' => '']
  49. );
  50. }
  51. public function testEmptyFormatValue(): void
  52. {
  53. $this->expectException(InvalidConfigurationException::class);
  54. $this->expectExceptionMessage('Expected "yes" or "no" for option "using-cache", got "not today".');
  55. $cmdTester = $this->doTestExecute(
  56. [
  57. '--using-cache' => 'not today',
  58. '--rules' => 'switch_case_semicolon_to_colon',
  59. ]
  60. );
  61. $cmdTester->getStatusCode();
  62. }
  63. /**
  64. * @covers \PhpCsFixer\Console\Command\WorkerCommand
  65. * @covers \PhpCsFixer\Runner\Runner::fixSequential
  66. */
  67. public function testSequentialRun(): void
  68. {
  69. $pathToDistConfig = __DIR__.'/../../../.php-cs-fixer.dist.php';
  70. $configWithFixedParallelConfig = <<<PHP
  71. <?php
  72. \$config = require '{$pathToDistConfig}';
  73. \$config->setRules(['header_comment' => ['header' => 'SEQUENTIAL!']]);
  74. \$config->setParallelConfig(\\PhpCsFixer\\Runner\\Parallel\\ParallelConfigFactory::sequential());
  75. return \$config;
  76. PHP;
  77. $tmpFile = tempnam(sys_get_temp_dir(), 'php-cs-fixer-parallel-config-').'.php';
  78. file_put_contents($tmpFile, $configWithFixedParallelConfig);
  79. $cmdTester = $this->doTestExecute(
  80. [
  81. '--config' => $tmpFile,
  82. 'path' => [__DIR__],
  83. ]
  84. );
  85. self::assertStringContainsString('Running analysis on 1 core sequentially.', $cmdTester->getDisplay());
  86. self::assertStringContainsString('You can enable parallel runner and speed up the analysis!', $cmdTester->getDisplay());
  87. self::assertStringContainsString('(header_comment)', $cmdTester->getDisplay());
  88. self::assertSame(8, $cmdTester->getStatusCode());
  89. }
  90. /**
  91. * There's no simple way to cover parallelisation with tests, because it involves a lot of hardcoded logic under the hood,
  92. * like opening server, communicating through sockets, etc. That's why we only test `fix` command with proper
  93. * parallel config, so runner utilises multi-processing internally. Expected outcome is information about utilising multiple CPUs.
  94. *
  95. * @covers \PhpCsFixer\Console\Command\WorkerCommand
  96. * @covers \PhpCsFixer\Runner\Runner::fixParallel
  97. */
  98. public function testParallelRun(): void
  99. {
  100. $pathToDistConfig = __DIR__.'/../../../.php-cs-fixer.dist.php';
  101. $configWithFixedParallelConfig = <<<PHP
  102. <?php
  103. \$config = require '{$pathToDistConfig}';
  104. \$config->setRules(['header_comment' => ['header' => 'PARALLEL!']]);
  105. \$config->setParallelConfig(new \\PhpCsFixer\\Runner\\Parallel\\ParallelConfig(2, 1, 300));
  106. return \$config;
  107. PHP;
  108. $tmpFile = tempnam(sys_get_temp_dir(), 'php-cs-fixer-parallel-config-').'.php';
  109. file_put_contents($tmpFile, $configWithFixedParallelConfig);
  110. $cmdTester = $this->doTestExecute(
  111. [
  112. '--config' => $tmpFile,
  113. 'path' => [__DIR__],
  114. ]
  115. );
  116. self::assertStringContainsString('Running analysis on 2 cores with 1 file per process.', $cmdTester->getDisplay());
  117. self::assertStringContainsString('Parallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!', $cmdTester->getDisplay());
  118. self::assertStringContainsString('(header_comment)', $cmdTester->getDisplay());
  119. self::assertSame(8, $cmdTester->getStatusCode());
  120. }
  121. /**
  122. * @param array<string, mixed> $arguments
  123. */
  124. private function doTestExecute(array $arguments): CommandTester
  125. {
  126. $application = new Application();
  127. $application->add(new FixCommand(new ToolInfo()));
  128. $command = $application->find('fix');
  129. $commandTester = new CommandTester($command);
  130. $commandTester->execute(
  131. array_merge(
  132. ['command' => $command->getName()],
  133. $this->getDefaultArguments(),
  134. $arguments
  135. ),
  136. [
  137. 'interactive' => false,
  138. 'decorated' => false,
  139. 'verbosity' => OutputInterface::VERBOSITY_DEBUG,
  140. ]
  141. );
  142. return $commandTester;
  143. }
  144. /**
  145. * @return array<string, mixed>
  146. */
  147. private function getDefaultArguments(): array
  148. {
  149. return [
  150. 'path' => [__FILE__],
  151. '--path-mode' => 'override',
  152. '--allow-risky' => 'yes',
  153. '--dry-run' => true,
  154. '--using-cache' => 'no',
  155. '--show-progress' => 'none',
  156. ];
  157. }
  158. }