diff --git a/README.md b/README.md index 7b304a02..616a7f2c 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,11 @@ ParaTest provides a dedicated binary to work with PHPStorm; follow these steps t You should now have a `ParaTest` run within your configurations list. It should natively work with the `Rerun failed tests` and `Toggle auto-test` buttons of the `Run` overlay. +### Run with Coverage + +Coverage with one of the [available coverage engines](#code-coverage) must already be [configured in PHPStorm](https://www.jetbrains.com/help/phpstorm/code-coverage.html) +and working when running tests sequentially in order for the helper binary to correctly handle code coverage + # For Contributors: testing ParaTest itself Before creating a Pull Request be sure to run all the necessary checks with `make` command. diff --git a/composer.json b/composer.json index e8c3dd11..7dd4b7cc 100644 --- a/composer.json +++ b/composer.json @@ -45,6 +45,7 @@ "phpunit/phpunit": "^9.5.21", "sebastian/environment": "^5.1.4", "symfony/console": "^5.4.9 || ^6.1.2", + "symfony/polyfill-php80": "^v1.26.0", "symfony/process": "^5.4.8 || ^6.1.0" }, "require-dev": { @@ -55,7 +56,7 @@ "malukenho/mcbumpface": "^1.1.5", "squizlabs/php_codesniffer": "^3.7.1", "symfony/filesystem": "^5.4.9 || ^6.1.0", - "vimeo/psalm": "^4.24.0" + "vimeo/psalm": "^4.26.0" }, "autoload": { "psr-4": { @@ -80,6 +81,7 @@ "dealerdirect/phpcodesniffer-composer-installer": true, "infection/extension-installer": true, "malukenho/mcbumpface": true - } + }, + "sort-packages": true } } diff --git a/src/Util/PhpstormHelper.php b/src/Util/PhpstormHelper.php index c271e4b5..4e2ecb31 100644 --- a/src/Util/PhpstormHelper.php +++ b/src/Util/PhpstormHelper.php @@ -4,8 +4,12 @@ namespace ParaTest\Util; +use RuntimeException; + +use function array_search; use function array_unshift; use function in_array; +use function str_ends_with; /** * @internal @@ -13,18 +17,25 @@ final class PhpstormHelper { /** - * @param array $argv + * @param array $argv */ public static function handleArgvFromPhpstorm(array &$argv, string $paratestBinary): string { + $phpunitKey = self::getArgvKeyFor($argv, 'vendor/phpunit/phpunit/phpunit'); + if (! in_array('--filter', $argv, true)) { - unset($argv[1]); + $coverageArgKey = self::getCoverageArgvKey($argv); + if ($coverageArgKey !== false) { + unset($argv[$coverageArgKey]); + } + + unset($argv[$phpunitKey]); return $paratestBinary; } - unset($argv[0]); - $phpunitBinary = $argv[1]; + unset($argv[self::getArgvKeyFor($argv, 'vendor/brianium/paratest/bin/paratest')]); + $phpunitBinary = $argv[$phpunitKey]; foreach ($argv as $index => $value) { if ($value === '--configuration' || $value === '--bootstrap') { break; @@ -37,4 +48,40 @@ public static function handleArgvFromPhpstorm(array &$argv, string $paratestBina return $phpunitBinary; } + + /** + * @param array $argv + */ + private static function getArgvKeyFor(array $argv, string $searchFor): int + { + foreach ($argv as $key => $arg) { + if (str_ends_with($arg, $searchFor)) { + return $key; + } + } + + throw new RuntimeException("Missing path to '$searchFor'"); + } + + /** + * @param array $argv + * + * @return int|false + */ + private static function getCoverageArgvKey(array $argv) + { + $coverageOptions = [ + '-dpcov.enabled=1', + '-dxdebug.mode=coverage', + ]; + + foreach ($coverageOptions as $coverageOption) { + $key = array_search($coverageOption, $argv, true); + if ($key !== false) { + return $key; + } + } + + return false; + } } diff --git a/test/Unit/Coverage/CoverageReporterTest.php b/test/Unit/Coverage/CoverageReporterTest.php index 4fd858d6..009320dd 100644 --- a/test/Unit/Coverage/CoverageReporterTest.php +++ b/test/Unit/Coverage/CoverageReporterTest.php @@ -39,7 +39,7 @@ private function createCoverageReporter(string $fixtureFile): void $codeCoverage = new CodeCoverage((new Selector())->forLineCoverage($filter), $filter); $codeCoverage->append(RawCodeCoverageData::fromXdebugWithoutPathCoverage([ __FILE__ => [__LINE__ => 1], - ]), uniqid()); + ]), uniqid('test_')); $configuration = (new Loader())->load($this->fixture($fixtureFile)); diff --git a/test/Unit/Util/PhpstormHelperTest.php b/test/Unit/Util/PhpstormHelperTest.php index da8ed402..18abd318 100644 --- a/test/Unit/Util/PhpstormHelperTest.php +++ b/test/Unit/Util/PhpstormHelperTest.php @@ -9,6 +9,7 @@ use PHPUnit\Framework\TestCase; use function array_values; +use function sprintf; use function uniqid; /** @@ -33,14 +34,14 @@ public function testWithoutFilterRunParaTest( $actualBinary = PhpstormHelper::handleArgvFromPhpstorm($argv, $paratestBinary); $argv = array_values($argv); - static::assertSame($expectedArgv, $argv); + self::assertSame($expectedArgv, $argv); self::assertSame($expectedBinary, $actualBinary); } public function providePhpstormCases(): Generator { - $paratestBinary = uniqid('paratest_'); - $phpunitBinary = uniqid('phpunit_'); + $paratestBinary = sprintf('%s/vendor/brianium/paratest/bin/paratest', uniqid()); + $phpunitBinary = sprintf('%s/vendor/phpunit/phpunit/phpunit', uniqid()); $argv = []; $argv[] = $paratestBinary; @@ -94,5 +95,88 @@ public function providePhpstormCases(): Generator $paratestBinary, $phpunitBinary, ]; + + $argv = []; + $argv[] = $paratestBinary; + $argv[] = '-dxdebug.mode=coverage'; + $argv[] = $phpunitBinary; + $argv[] = '--runner'; + $argv[] = 'WrapperRunner'; + $argv[] = '--coverage-clover'; + $argv[] = '/home/user/repos/test/coverage.xml'; + $argv[] = '--configuration'; + $argv[] = '/home/user/repos/test/phpunit.xml'; + $argv[] = '--teamcity'; + + $expected = []; + $expected[] = $paratestBinary; + $expected[] = '--runner'; + $expected[] = 'WrapperRunner'; + $expected[] = '--coverage-clover'; + $expected[] = '/home/user/repos/test/coverage.xml'; + $expected[] = '--configuration'; + $expected[] = '/home/user/repos/test/phpunit.xml'; + $expected[] = '--teamcity'; + + yield 'with -dxdebug.mode=coverage run ParaTest' => [ + $argv, + $expected, + $paratestBinary, + $paratestBinary, + ]; + + $argv = []; + $argv[] = $paratestBinary; + $argv[] = '-dxdebug.mode=coverage'; + $argv[] = $phpunitBinary; + $argv[] = '--coverage-clover'; + $argv[] = '/home/user/repos/test/coverage.xml'; + $argv[] = '--configuration'; + $argv[] = '/home/user/repos/test/phpunit.xml'; + $argv[] = '--teamcity'; + + $expected = []; + $expected[] = $paratestBinary; + $expected[] = '--coverage-clover'; + $expected[] = '/home/user/repos/test/coverage.xml'; + $expected[] = '--configuration'; + $expected[] = '/home/user/repos/test/phpunit.xml'; + $expected[] = '--teamcity'; + + yield 'with -dxdebug.mode=coverage and no wrapper run ParaTest' => [ + $argv, + $expected, + $paratestBinary, + $paratestBinary, + ]; + + $argv = []; + $argv[] = $paratestBinary; + $argv[] = '-dpcov.enabled=1'; + $argv[] = $phpunitBinary; + $argv[] = '--runner'; + $argv[] = 'WrapperRunner'; + $argv[] = '--coverage-clover'; + $argv[] = '/home/user/repos/test/coverage.xml'; + $argv[] = '--configuration'; + $argv[] = '/home/user/repos/test/phpunit.xml'; + $argv[] = '--teamcity'; + + $expected = []; + $expected[] = $paratestBinary; + $expected[] = '--runner'; + $expected[] = 'WrapperRunner'; + $expected[] = '--coverage-clover'; + $expected[] = '/home/user/repos/test/coverage.xml'; + $expected[] = '--configuration'; + $expected[] = '/home/user/repos/test/phpunit.xml'; + $expected[] = '--teamcity'; + + yield 'with -dpcov.enabled=1 run ParaTest' => [ + $argv, + $expected, + $paratestBinary, + $paratestBinary, + ]; } }