From 299609af19a9a547944e395742a8315dc2ecadff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20HULARD?= Date: Wed, 6 Mar 2024 10:09:41 +0100 Subject: [PATCH 1/3] phpunit: Allow compatibility with php-code-coverage v11.* Also require phpunit/php-file-iterator which is used to find the files to include. --- composer.json | 3 ++- src/Listener/CodeCoverageListener.php | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index bac9159..0887ba3 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,8 @@ "require": { "php": ">= 7.3", "phpspec/phpspec": "^6.0 || ^7.0", - "phpunit/php-code-coverage": "^9.2 || ^10.0" + "phpunit/php-code-coverage": "^9.2 || ^10.0 || ^11.0", + "phpunit/php-file-iterator": "^3.0 || ^4.0 || ^5.0" }, "require-dev": { "phpstan/phpstan": "^1.5", diff --git a/src/Listener/CodeCoverageListener.php b/src/Listener/CodeCoverageListener.php index 75efd49..5cf40dc 100644 --- a/src/Listener/CodeCoverageListener.php +++ b/src/Listener/CodeCoverageListener.php @@ -21,6 +21,7 @@ use SebastianBergmann\CodeCoverage\CodeCoverage; use SebastianBergmann\CodeCoverage\Report; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; use function gettype; use function is_array; @@ -153,12 +154,16 @@ public function beforeSuite(SuiteEvent $event): void foreach ($this->options['whitelist'] as $option) { $settings = $this->filterDirectoryParams($option); - $filter->includeDirectory($settings['directory'], $settings['suffix'], $settings['prefix']); + foreach ((new FileIteratorFacade())->getFilesAsArray($settings['directory'], $settings['suffix'], $settings['prefix']) as $file) { + $filter->includeFile($file); + } } foreach ($this->options['blacklist'] as $option) { $settings = $this->filterDirectoryParams($option); - + foreach ((new FileIteratorFacade)->getFilesAsArray($directory, $suffix, $prefix) as $file) { + $filter->excludeFile($file); + } $filter->excludeDirectory($settings['directory'], $settings['suffix'], $settings['prefix']); } From 3e150d9566a9984b5f496c447114473ecd0fe0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20HULARD?= Date: Wed, 6 Mar 2024 10:11:09 +0100 Subject: [PATCH 2/3] doc: Update phpunit supported version matrix. --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2573c69..c44f5a7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![GitHub Workflow Status](https://github.com/friends-of-phpspec/phpspec-code-coverage/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/friends-of-phpspec/phpspec-code-coverage/actions) [![Scrutinizer code quality](https://img.shields.io/scrutinizer/quality/g/friends-of-phpspec/phpspec-code-coverage/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/friends-of-phpspec/phpspec-code-coverage/?branch=master) [![License](https://img.shields.io/packagist/l/friends-of-phpspec/phpspec-code-coverage.svg?style=flat-square)](https://packagist.org/packages/friends-of-phpspec/phpspec-code-coverage) - + # phpspec-code-coverage [phpspec-code-coverage][0] is a [PhpSpec][2] extension that generates Code @@ -22,14 +22,14 @@ used as a single metric defining how good your tests are. - PHP 7+ (for [PhpSpec][2] v4+) or PHP 5.6+ (for [PhpSpec][2] v3) - [Xdebug][3], [phpdbg][4] or [pcov][6] extension enabled (PHP 7+ is required for code generation to work with [phpdbg][4]). - + ## Compatibility -| phpspec-code-coverage | PHP | phpspec | phpunit | -|-----------------------|----------|----------------------------|----------------------------| -| 4.x | `^7.1` | `^4.2 \|\| ^5.0 \|\| ^6.0` | `^5.0 \|\| ^6.0 \|\| ^7.0` | -| 5.x | `>= 7.2` | `^5.0 \|\| ^6.0 \|\| ^7.0` | `^6.0 \|\| ^7.0 \|\| ^8.0` | -| 6.x | `>= 7.3` | `^6.0 \|\| ^7.0` | `^9.0` | +| phpspec-code-coverage | PHP | phpspec | phpunit | +|-----------------------|----------|----------------------------|------------------------------| +| 4.x | `^7.1` | `^4.2 \|\| ^5.0 \|\| ^6.0` | `^5.0 \|\| ^6.0 \|\| ^7.0` | +| 5.x | `>= 7.2` | `^5.0 \|\| ^6.0 \|\| ^7.0` | `^6.0 \|\| ^7.0 \|\| ^8.0` | +| 6.x | `>= 7.3` | `^6.0 \|\| ^7.0` | `^9.2 \|\| ^10.0 \|\| ^11.0` | ## Change Log @@ -171,11 +171,11 @@ extensions: * `high_lower_bound` (optional) sets high lower bound for code coverage (default `70`) * `whitelist` takes an array of directories to whitelist (default: `lib`, - `src`). The array can be made more specific if an associative array is + `src`). The array can be made more specific if an associative array is given with the following keys (`directory`, `prefix`, `suffix`) * `whitelist_files` takes an array of files to whitelist (default: none). * `blacklist` takes an array of directories to blacklist (default: `test, - vendor, spec`). The array can be made more specific if an associative + vendor, spec`). The array can be made more specific if an associative array is given with the following keys (`directory`, `prefix`, `suffix`) * `blacklist_files` takes an array of files to blacklist From 1dc3e641f0e9abe27713a5ad46206fd2a2af9747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20HULARD?= Date: Mon, 15 Jul 2024 13:44:41 +0200 Subject: [PATCH 3/3] chore: Handle blacklist and blacklist_files options. Since the phpunit/php-code-coverage isn't able to exclude any folder from version 11, we must handle that logic differently. We now compute a list of files and folder to be excluded and we give it to the filter. --- spec/Listener/CodeCoverageListenerSpec.php | 11 +++++ src/Listener/CodeCoverageListener.php | 48 ++++++++++++---------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/spec/Listener/CodeCoverageListenerSpec.php b/spec/Listener/CodeCoverageListenerSpec.php index 8c53a86..357da7b 100644 --- a/spec/Listener/CodeCoverageListenerSpec.php +++ b/spec/Listener/CodeCoverageListenerSpec.php @@ -35,12 +35,23 @@ public function let(ConsoleIO $io, Driver $driver) public function it_can_process_all_directory_filtering_options(SuiteEvent $event) { $this->setOptions([ + 'whitelist' => [ + 'src', + ['directory' => 'src', 'suffix' => 'Spec.php', 'prefix' => 'Get'], + ['directory' => 'src', 'suffix' => 'Test.php'], + ['directory' => 'src'], + ], + 'whitelist_files' => 'path/to/file.php', 'blacklist' => [ 'src', ['directory' => 'src', 'suffix' => 'Spec.php', 'prefix' => 'Get'], ['directory' => 'src', 'suffix' => 'Test.php'], ['directory' => 'src'], ], + 'blacklist_files' => [ + 'path/to/file.php', + 'path/to/file2.php' + ] ]); $this diff --git a/src/Listener/CodeCoverageListener.php b/src/Listener/CodeCoverageListener.php index 5cf40dc..c43c1e1 100644 --- a/src/Listener/CodeCoverageListener.php +++ b/src/Listener/CodeCoverageListener.php @@ -20,8 +20,8 @@ use PhpSpec\Event\SuiteEvent; use SebastianBergmann\CodeCoverage\CodeCoverage; use SebastianBergmann\CodeCoverage\Report; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; use function gettype; use function is_array; @@ -139,10 +139,6 @@ public function beforeExample(ExampleEvent $event): void $this->coverage->start($name); } - /** - * Note: We use array_map() instead of array_walk() because the latter expects - * the callback to take the value as the first and the index as the seconds parameter. - */ public function beforeSuite(SuiteEvent $event): void { if ($this->skipCoverage) { @@ -151,26 +147,36 @@ public function beforeSuite(SuiteEvent $event): void $filter = $this->coverage->filter(); - foreach ($this->options['whitelist'] as $option) { + // We compute the list of file / folder to be excluded + // If the blacklist contains suffixes and/or prefixes, we extract an + // exhaustive list of files that match to be added in the excluded list. + $excludes = $this->options['blacklist_files']; + foreach ($this->options['blacklist'] as $option) { $settings = $this->filterDirectoryParams($option); - - foreach ((new FileIteratorFacade())->getFilesAsArray($settings['directory'], $settings['suffix'], $settings['prefix']) as $file) { - $filter->includeFile($file); + if (!empty($settings['suffix']) || !empty($settings['prefix'])) { + $excludes = $excludes + (new FileIteratorFacade())->getFilesAsArray( + $settings['directory'], + $settings['suffix'], + $settings['prefix'] + ); + } else { + $excludes[] = $settings['directory']; } } - foreach ($this->options['blacklist'] as $option) { + foreach ($this->options['whitelist'] as $option) { $settings = $this->filterDirectoryParams($option); - foreach ((new FileIteratorFacade)->getFilesAsArray($directory, $suffix, $prefix) as $file) { - $filter->excludeFile($file); + $fileIterator = (new FileIteratorFacade())->getFilesAsArray( + [$settings['directory']] + $this->options['whitelist_files'], + $settings['suffix'], + $settings['prefix'], + // We exclude the files from the previously built list. + $excludes + ); + + foreach ($fileIterator as $file) { + $filter->includeFile($file); } - $filter->excludeDirectory($settings['directory'], $settings['suffix'], $settings['prefix']); - } - - $filter->includeFiles($this->options['whitelist_files']); - - foreach ($this->options['blacklist_files'] as $option) { - $filter->excludeFile($option); } } @@ -198,7 +204,7 @@ public function setOptions(array $options): void /** * @param array|string $option * - * @return array{directory:string, prefix:string, suffix:string} + * @return array{directory:non-empty-string, prefix:string, suffix:string} */ protected function filterDirectoryParams($option): array { @@ -213,7 +219,7 @@ protected function filterDirectoryParams($option): array )); } - if (!isset($option['directory'])) { + if (empty($option['directory'])) { throw new ConfigurationException('Missing required directory path.'); }