CiIntegrationTest.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. <?php
  2. /*
  3. * This file is part of PHP CS Fixer.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. namespace PhpCsFixer\Tests\Smoke;
  12. use Keradus\CliExecutor\CommandExecutor;
  13. use Keradus\CliExecutor\ScriptExecutor;
  14. /**
  15. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  16. *
  17. * @internal
  18. *
  19. * @requires OS Linux|Darwin
  20. * @coversNothing
  21. * @group covers-nothing
  22. * @large
  23. */
  24. final class CiIntegrationTest extends AbstractSmokeTest
  25. {
  26. public static $fixtureDir;
  27. public static function setUpBeforeClass()
  28. {
  29. parent::setUpBeforeClass();
  30. self::$fixtureDir = __DIR__.'/../Fixtures/ci-integration';
  31. try {
  32. CommandExecutor::create('composer --version', __DIR__)->getResult();
  33. } catch (\RuntimeException $e) {
  34. self::markTestSkippedOrFail('Missing `composer` env script. Details:'."\n".$e->getMessage());
  35. }
  36. try {
  37. CommandExecutor::create('composer check', __DIR__.'/../..')->getResult();
  38. } catch (\RuntimeException $e) {
  39. self::markTestSkippedOrFail('Composer check failed. Details:'."\n".$e->getMessage());
  40. }
  41. try {
  42. self::executeScript([
  43. 'rm -rf .git',
  44. 'git init -q',
  45. 'git config user.name test',
  46. 'git config user.email test',
  47. 'git add .',
  48. 'git commit -m "init" -q',
  49. ]);
  50. } catch (\RuntimeException $e) {
  51. self::markTestSkippedOrFail($e->getMessage());
  52. }
  53. }
  54. public static function tearDownAfterClass()
  55. {
  56. parent::tearDownAfterClass();
  57. self::executeCommand('rm -rf .git');
  58. }
  59. protected function tearDown()
  60. {
  61. parent::tearDown();
  62. self::executeScript([
  63. 'git reset . -q',
  64. 'git checkout . -q',
  65. 'git clean -fdq',
  66. 'git checkout master -q',
  67. ]);
  68. }
  69. /**
  70. * @param string $branchName
  71. * @param string[] $caseCommands
  72. * @param string[] $expectedResult1Lines
  73. * @param string[] $expectedResult2Lines
  74. * @param string $expectedResult3Files
  75. *
  76. * @dataProvider provideIntegrationCases
  77. */
  78. public function testIntegration(
  79. $branchName,
  80. array $caseCommands,
  81. array $expectedResult1Lines,
  82. array $expectedResult2Lines,
  83. $expectedResult3Files
  84. ) {
  85. self::executeScript(array_merge(
  86. [
  87. "git checkout -b ${branchName} -q",
  88. ],
  89. $caseCommands
  90. ));
  91. $integrationScript = explode("\n", str_replace('vendor/bin/', './../../../', file_get_contents(__DIR__.'/../../dev-tools/ci-integration.sh')));
  92. $steps = [
  93. "COMMIT_RANGE=\"master..${branchName}\"",
  94. "{$integrationScript[3]}\n{$integrationScript[4]}",
  95. $integrationScript[5],
  96. $integrationScript[6],
  97. $integrationScript[7],
  98. ];
  99. $result1 = self::executeScript([
  100. $steps[0],
  101. $steps[1],
  102. $steps[2],
  103. 'echo "$CHANGED_FILES"',
  104. ]);
  105. $this->assertSame(implode("\n", $expectedResult1Lines)."\n", $result1->getOutput());
  106. $result2 = self::executeScript([
  107. $steps[0],
  108. $steps[1],
  109. $steps[2],
  110. $steps[3],
  111. 'echo "${EXTRA_ARGS}"',
  112. ]);
  113. $this->assertSame(implode("\n", $expectedResult2Lines), $result2->getOutput());
  114. $result3 = self::executeScript([
  115. $steps[0],
  116. $steps[1],
  117. $steps[2],
  118. $steps[3],
  119. $steps[4],
  120. ]);
  121. $optionalIncompatibilityWarning = 'PHP needs to be a minimum version of PHP 5.6.0 and maximum version of PHP 7.3.*.
  122. Ignoring environment requirements because `PHP_CS_FIXER_IGNORE_ENV` is set. Execution may be unstable.
  123. ';
  124. $optionalXdebugWarning = 'You are running PHP CS Fixer with xdebug enabled. This has a major impact on runtime performance.
  125. If you need help while solving warnings, ask at https://gitter.im/PHP-CS-Fixer, we will help you!
  126. ';
  127. $pattern = sprintf(
  128. '/^(?:%s)?(?:%s)?%s\n([\.S]{%d})\n%s$/',
  129. preg_quote($optionalIncompatibilityWarning, '/'),
  130. preg_quote($optionalXdebugWarning, '/'),
  131. preg_quote('Loaded config default from ".php_cs.dist".', '/'),
  132. \strlen($expectedResult3Files),
  133. preg_quote('Legend: ?-unknown, I-invalid file syntax, file ignored, S-Skipped, .-no changes, F-fixed, E-error', '/')
  134. );
  135. $this->assertRegExp($pattern, $result3->getError());
  136. preg_match($pattern, $result3->getError(), $matches);
  137. $this->assertArrayHasKey(1, $matches);
  138. $this->assertSame(substr_count($expectedResult3Files, '.'), substr_count($matches[1], '.'));
  139. $this->assertSame(substr_count($expectedResult3Files, 'S'), substr_count($matches[1], 'S'));
  140. $this->assertRegExp(
  141. '/^\s*Checked all files in \d+\.\d+ seconds, \d+\.\d+ MB memory used\s*$/',
  142. $result3->getOutput()
  143. );
  144. }
  145. public function provideIntegrationCases()
  146. {
  147. return [
  148. 'random-changes' => [
  149. 'random-changes',
  150. [
  151. 'touch dir\ a/file.php',
  152. 'rm -r dir\ c',
  153. 'echo "" >> dir\ b/file\ b.php',
  154. 'echo "echo 1;" >> dir\ b/file\ b.php',
  155. 'git add .',
  156. 'git commit -m "Random changes" -q',
  157. ],
  158. [
  159. 'dir a/file.php',
  160. 'dir b/file b.php',
  161. ],
  162. [
  163. '--path-mode=intersection',
  164. '--',
  165. 'dir a/file.php',
  166. 'dir b/file b.php',
  167. '',
  168. ],
  169. 'S.',
  170. ],
  171. 'changes-including-dist-config-file' => [
  172. 'changes-including-dist-config-file',
  173. [
  174. 'echo "" >> dir\ b/file\ b.php',
  175. 'echo "echo 1;" >> dir\ b/file\ b.php',
  176. // `sed -i ...` is not handled the same on Linux and macOS
  177. 'sed -e \'s/@Symfony/@PSR2/\' .php_cs.dist > .php_cs.dist.new',
  178. 'mv .php_cs.dist.new .php_cs.dist',
  179. 'git add .',
  180. 'git commit -m "Random changes including config file" -q',
  181. ],
  182. [
  183. '.php_cs.dist',
  184. 'dir b/file b.php',
  185. ],
  186. [
  187. '',
  188. '',
  189. ],
  190. '...',
  191. ],
  192. 'changes-including-custom-config-file-creation' => [
  193. 'changes-including-custom-config-file-creation',
  194. [
  195. 'echo "" >> dir\ b/file\ b.php',
  196. 'echo "echo 1;" >> dir\ b/file\ b.php',
  197. 'sed -e \'s/@Symfony/@PSR2/\' .php_cs.dist > .php_cs',
  198. 'git add .',
  199. 'git commit -m "Random changes including custom config file creation" -q',
  200. ],
  201. [
  202. '.php_cs',
  203. 'dir b/file b.php',
  204. ],
  205. [
  206. '',
  207. '',
  208. ],
  209. '...',
  210. ],
  211. 'changes-including-composer-lock' => [
  212. 'changes-including-composer-lock',
  213. [
  214. 'echo "" >> dir\ b/file\ b.php',
  215. 'echo "echo 1;" >> dir\ b/file\ b.php',
  216. 'touch composer.lock',
  217. 'git add .',
  218. 'git commit -m "Random changes including composer.lock" -q',
  219. ],
  220. [
  221. 'composer.lock',
  222. 'dir b/file b.php',
  223. ],
  224. [
  225. '',
  226. '',
  227. ],
  228. '...',
  229. ],
  230. ];
  231. }
  232. private static function executeCommand($command)
  233. {
  234. return CommandExecutor::create($command, self::$fixtureDir)->getResult();
  235. }
  236. private static function executeScript(array $scriptParts)
  237. {
  238. return ScriptExecutor::create($scriptParts, self::$fixtureDir)->getResult();
  239. }
  240. }