From dac49419e9895a476cb79b4428150a42f057dc7e Mon Sep 17 00:00:00 2001 From: Balazs Csaba Date: Sat, 5 Jul 2025 10:05:32 +0300 Subject: [PATCH 1/3] Fix compatibility with latest phpspec container --- phpstan.neon | 10 ++++ src/CodeCoverageExtension.php | 48 ++++++++-------- src/CodeCoverageOptions.php | 105 ++++++++++++++++++++++++++++++++++ src/CodeCoverageReports.php | 62 ++++++++++++++++++++ 4 files changed, 202 insertions(+), 23 deletions(-) create mode 100644 src/CodeCoverageOptions.php create mode 100644 src/CodeCoverageReports.php diff --git a/phpstan.neon b/phpstan.neon index b756e79..64b8149 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -7,4 +7,14 @@ parameters: # phpstan has hard time to check whenever we are using PHPUnit 10 or PHPUnit 9 - message: '#Class SebastianBergmann\\CodeCoverage\\Report\\Text constructor invoked with 4 parameters, 1-3 required\.#' + count: 1 path: ./src/CodeCoverageExtension.php + - + message: "#^Parameter \\#1 \\$thresholds of class SebastianBergmann\\\\CodeCoverage\\\\Report\\\\Text constructor expects SebastianBergmann\\\\CodeCoverage\\\\Report\\\\Thresholds, int given\\.$#" + count: 1 + path: src/CodeCoverageExtension.php + + - + message: "#^Parameter \\#2 \\$showUncoveredFiles of class SebastianBergmann\\\\CodeCoverage\\\\Report\\\\Text constructor expects bool, int given\\.$#" + count: 1 + path: src/CodeCoverageExtension.php diff --git a/src/CodeCoverageExtension.php b/src/CodeCoverageExtension.php index b593053..0972040 100644 --- a/src/CodeCoverageExtension.php +++ b/src/CodeCoverageExtension.php @@ -100,62 +100,56 @@ public function load(ServiceContainer $container, array $params = []): void $options['show_only_summary'] = false; } - return $options; + return new CodeCoverageOptions($options); }); $container->define('code_coverage.reports', static function (ServiceContainer $container) { - /** @var array $options */ - $options = $container->get('code_coverage.options'); + /** @var CodeCoverageOptions $optionsWrapper */ + $optionsWrapper = $container->get('code_coverage.options'); + $options = $optionsWrapper->getOptions(); $reports = []; - foreach ($options['format'] as $format) { + foreach ($optionsWrapper->getFormats() as $format) { switch ($format) { case 'clover': $reports['clover'] = new Report\Clover(); - break; case 'php': $reports['php'] = new Report\PHP(); - break; case 'text': $reports['text'] = version_compare(Version::id(), '10.0.0', '>=') && class_exists(Thresholds::class) ? new Report\Text( - Thresholds::from($options['lower_upper_bound'], $options['high_lower_bound']), - $options['show_uncovered_files'], - $options['show_only_summary'] + Thresholds::from($optionsWrapper->getLowerUpperBound(), $optionsWrapper->getHighLowerBound()), + $optionsWrapper->showUncoveredFiles(), + $optionsWrapper->showOnlySummary() ) : new Report\Text( - $options['lower_upper_bound'], - $options['high_lower_bound'], - $options['show_uncovered_files'], - $options['show_only_summary'] + $optionsWrapper->getLowerUpperBound(), + $optionsWrapper->getHighLowerBound(), + $optionsWrapper->showUncoveredFiles(), + $optionsWrapper->showOnlySummary() ); - break; case 'xml': $reports['xml'] = new Report\Xml\Facade(Version::id()); - break; case 'crap4j': $reports['crap4j'] = new Report\Crap4j(); - break; case 'html': $reports['html'] = new Report\Html\Facade(); - break; case 'cobertura': $reports['cobertura'] = new Report\Cobertura(); - break; } } $container->setParam('code_coverage', $options); - return $reports; + return new CodeCoverageReports($reports); }); $container->define('event_dispatcher.listeners.code_coverage', static function (ServiceContainer $container) { @@ -169,11 +163,19 @@ public function load(ServiceContainer $container, array $params = []): void /** @var CodeCoverage $codeCoverage */ $codeCoverage = $container->get('code_coverage'); - /** @var array $codeCoverageReports */ - $codeCoverageReports = $container->get('code_coverage.reports'); + /** @var CodeCoverageReports $codeCoverageReportsWrapper */ + $codeCoverageReportsWrapper = $container->get('code_coverage.reports'); + + /** @var CodeCoverageOptions $optionsWrapper */ + $optionsWrapper = $container->get('code_coverage.options'); - $listener = new CodeCoverageListener($consoleIO, $codeCoverage, $codeCoverageReports, $skipCoverage); - $listener->setOptions($container->getParam('code_coverage', [])); + $listener = new CodeCoverageListener( + $consoleIO, + $codeCoverage, + $codeCoverageReportsWrapper->getReports(), + $skipCoverage + ); + $listener->setOptions($optionsWrapper->getOptions()); return $listener; }, ['event_dispatcher.listeners']); diff --git a/src/CodeCoverageOptions.php b/src/CodeCoverageOptions.php new file mode 100644 index 0000000..22e0032 --- /dev/null +++ b/src/CodeCoverageOptions.php @@ -0,0 +1,105 @@ + + * @license MIT + * + * For the full copyright and license information, please see the LICENSE file + * that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace FriendsOfPhpSpec\PhpSpec\CodeCoverage; + +class CodeCoverageOptions +{ + /** + * @var array + */ + private $options; + + /** + * @param array $options + */ + public function __construct(array $options) + { + $this->options = $options; + } + + /** + * @return array + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * @return mixed + */ + public function get(string $key) + { + return $this->options[$key] ?? null; + } + + /** + * @param mixed $default + * + * @return mixed + */ + public function getWithDefault(string $key, $default) + { + return $this->options[$key] ?? $default; + } + + /** + * @return array + */ + public function getFormats(): array + { + return $this->options['format'] ?? ['html']; + } + + /** + * @return array + */ + public function getOutputPaths(): array + { + return $this->options['output'] ?? []; + } + + /** + * @return bool + */ + public function showUncoveredFiles(): bool + { + return $this->options['show_uncovered_files'] ?? true; + } + + /** + * @return int + */ + public function getLowerUpperBound(): int + { + return $this->options['lower_upper_bound'] ?? 35; + } + + /** + * @return int + */ + public function getHighLowerBound(): int + { + return $this->options['high_lower_bound'] ?? 70; + } + + /** + * @return bool + */ + public function showOnlySummary(): bool + { + return $this->options['show_only_summary'] ?? false; + } +} diff --git a/src/CodeCoverageReports.php b/src/CodeCoverageReports.php new file mode 100644 index 0000000..05b5ef4 --- /dev/null +++ b/src/CodeCoverageReports.php @@ -0,0 +1,62 @@ + + * @license MIT + * + * For the full copyright and license information, please see the LICENSE file + * that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace FriendsOfPhpSpec\PhpSpec\CodeCoverage; + +class CodeCoverageReports +{ + /** + * @var array + */ + private $reports; + + /** + * @param array $reports + */ + public function __construct(array $reports) + { + $this->reports = $reports; + } + + /** + * @return array + */ + public function getReports(): array + { + return $this->reports; + } + + public function getReport(string $format): ?object + { + return $this->reports[$format] ?? null; + } + + /** + * @return array + */ + public function getAvailableFormats(): array + { + return array_keys($this->reports); + } + + public function hasReport(string $format): bool + { + return isset($this->reports[$format]); + } + + public function count(): int + { + return count($this->reports); + } +} From 693b85206e45f4ac4d94182c7450dea95dd34702 Mon Sep 17 00:00:00 2001 From: Balazs Csaba Date: Tue, 15 Jul 2025 11:22:02 +0300 Subject: [PATCH 2/3] Fixed spec tests --- spec/CodeCoverageExtensionSpec.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/spec/CodeCoverageExtensionSpec.php b/spec/CodeCoverageExtensionSpec.php index 411a013..256f52f 100644 --- a/spec/CodeCoverageExtensionSpec.php +++ b/spec/CodeCoverageExtensionSpec.php @@ -6,6 +6,7 @@ use Exception; use FriendsOfPhpSpec\PhpSpec\CodeCoverage\CodeCoverageExtension; +use FriendsOfPhpSpec\PhpSpec\CodeCoverage\CodeCoverageOptions; use PhpSpec\ObjectBehavior; use PhpSpec\ServiceContainer\IndexedServiceContainer; @@ -25,9 +26,10 @@ public function it_should_allow_to_set_show_only_summary_option(): void $container->setParam('code_coverage', ['show_only_summary' => true]); $this->load($container); + /** @var CodeCoverageOptions $options */ $options = $container->get('code_coverage.options'); - if (true !== $options['show_only_summary']) { + if (true !== $options->showOnlySummary()) { throw new Exception('show_only_summary was not set'); } } @@ -37,9 +39,10 @@ public function it_should_not_use_show_only_summary_option_by_default(): void $container = new IndexedServiceContainer(); $this->load($container, []); + /** @var CodeCoverageOptions $options */ $options = $container->get('code_coverage.options'); - if (false !== $options['show_only_summary']) { + if (false !== $options->showOnlySummary()) { throw new Exception('show_only_summary should be `false` by default'); } } @@ -50,9 +53,10 @@ public function it_should_transform_format_into_array(): void $container->setParam('code_coverage', ['format' => 'html']); $this->load($container); + /** @var CodeCoverageOptions $options */ $options = $container->get('code_coverage.options'); - if ($options['format'] !== ['html']) { + if ($options->getFormats() !== ['html']) { throw new Exception('Default format is not transformed to an array'); } } @@ -62,9 +66,10 @@ public function it_should_use_html_format_by_default(): void $container = new IndexedServiceContainer(); $this->load($container, []); + /** @var CodeCoverageOptions $options */ $options = $container->get('code_coverage.options'); - if ($options['format'] !== ['html']) { + if ($options->getFormats() !== ['html']) { throw new Exception('Default format is not html'); } } @@ -75,9 +80,10 @@ public function it_should_use_singular_output(): void $container->setParam('code_coverage', ['output' => 'test', 'format' => 'foo']); $this->load($container); + /** @var CodeCoverageOptions $options */ $options = $container->get('code_coverage.options'); - if (['foo' => 'test'] !== $options['output']) { + if (['foo' => 'test'] !== $options->getOutputPaths()) { throw new Exception('Default format is not singular output'); } } From 03663fbf70a8952122649dd1c6fdbb4eca3e5da1 Mon Sep 17 00:00:00 2001 From: Balazs Csaba Date: Wed, 16 Jul 2025 11:54:59 +0300 Subject: [PATCH 3/3] Ignored PHPStan issue on phpunit/php-code-coverage < 10.0 --- src/CodeCoverageExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CodeCoverageExtension.php b/src/CodeCoverageExtension.php index 0972040..b264969 100644 --- a/src/CodeCoverageExtension.php +++ b/src/CodeCoverageExtension.php @@ -122,7 +122,7 @@ public function load(ServiceContainer $container, array $params = []): void $reports['text'] = version_compare(Version::id(), '10.0.0', '>=') && class_exists(Thresholds::class) ? new Report\Text( Thresholds::from($optionsWrapper->getLowerUpperBound(), $optionsWrapper->getHighLowerBound()), - $optionsWrapper->showUncoveredFiles(), + $optionsWrapper->showUncoveredFiles(), // @phpstan-ignore-line Version 10.0.0+ uses Thresholds $optionsWrapper->showOnlySummary() ) : new Report\Text(