From 5d32dd06417a6b1f1f1cc18ce1485ecfd5c6e860 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Sun, 1 Dec 2024 22:45:31 +0000 Subject: [PATCH] feat: option to coverage --- src/Plugins/Coverage.php | 44 +++++++++++++++++++++++++++++++++--- tests/.snapshots/success.txt | 2 +- tests/Plugins/Coverage.php | 23 +++++++++++++++++++ tests/Visual/Parallel.php | 2 +- 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 tests/Plugins/Coverage.php diff --git a/src/Plugins/Coverage.php b/src/Plugins/Coverage.php index 5edf3933..75b06320 100644 --- a/src/Plugins/Coverage.php +++ b/src/Plugins/Coverage.php @@ -27,6 +27,11 @@ final class Coverage implements AddsOutput, HandlesArguments */ private const MIN_OPTION = 'min'; + /** + * @var string + */ + private const EXACTLY_OPTION = 'exactly'; + /** * Whether it should show the coverage or not. */ @@ -37,6 +42,11 @@ final class Coverage implements AddsOutput, HandlesArguments */ public float $coverageMin = 0.0; + /** + * The exactly coverage. + */ + public ?float $coverageExactly = null; + /** * Creates a new Plugin instance. */ @@ -51,7 +61,7 @@ public function __construct(private readonly OutputInterface $output) public function handleArguments(array $originals): array { $arguments = [...[''], ...array_values(array_filter($originals, function (string $original): bool { - foreach ([self::COVERAGE_OPTION, self::MIN_OPTION] as $option) { + foreach ([self::COVERAGE_OPTION, self::MIN_OPTION, self::EXACTLY_OPTION] as $option) { if ($original === sprintf('--%s', $option)) { return true; } @@ -73,6 +83,7 @@ public function handleArguments(array $originals): array $inputs = []; $inputs[] = new InputOption(self::COVERAGE_OPTION, null, InputOption::VALUE_NONE); $inputs[] = new InputOption(self::MIN_OPTION, null, InputOption::VALUE_REQUIRED); + $inputs[] = new InputOption(self::EXACTLY_OPTION, null, InputOption::VALUE_REQUIRED); $input = new ArgvInput($arguments, new InputDefinition($inputs)); if ((bool) $input->getOption(self::COVERAGE_OPTION)) { @@ -106,6 +117,13 @@ public function handleArguments(array $originals): array $this->coverageMin = (float) $minOption; } + if ($input->getOption(self::EXACTLY_OPTION) !== null) { + /** @var int|float $exactlyOption */ + $exactlyOption = $input->getOption(self::EXACTLY_OPTION); + + $this->coverageExactly = (float) $exactlyOption; + } + return $originals; } @@ -127,10 +145,22 @@ public function addOutput(int $exitCode): int } $coverage = \Pest\Support\Coverage::report($this->output); - $exitCode = (int) ($coverage < $this->coverageMin); - if ($exitCode === 1) { + if ($exitCode === 0 && $this->coverageExactly !== null) { + $comparableCoverage = $this->computeComparableCoverage($coverage); + $comparableCoverageExactly = $this->computeComparableCoverage($this->coverageExactly); + + $exitCode = $comparableCoverage === $comparableCoverageExactly ? 0 : 1; + + if ($exitCode === 1) { + $this->output->writeln(sprintf( + "\n FAIL Code coverage not exactly %s %%, currently %s %%.", + number_format($this->coverageExactly, 1), + number_format(floor($coverage * 10) / 10, 1), + )); + } + } elseif ($exitCode === 1) { $this->output->writeln(sprintf( "\n FAIL Code coverage below expected %s %%, currently %s %%.", number_format($this->coverageMin, 1), @@ -143,4 +173,12 @@ public function addOutput(int $exitCode): int return $exitCode; } + + /** + * Computes the comparable coverage to a percentage with one decimal. + */ + private function computeComparableCoverage(float $coverage): float + { + return floor($coverage * 10) / 10; + } } diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 1eaf4598..d48fba00 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -1698,4 +1698,4 @@ WARN Tests\Visual\Version - visual snapshot of help command output - Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 33 skipped, 1144 passed (2736 assertions) \ No newline at end of file + Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 24 skipped, 1142 passed (2720 assertions) diff --git a/tests/Plugins/Coverage.php b/tests/Plugins/Coverage.php new file mode 100644 index 00000000..4e2bfc4d --- /dev/null +++ b/tests/Plugins/Coverage.php @@ -0,0 +1,23 @@ + $this->computeComparableCoverage($givenValue))->call($plugin); + + expect($comparableCoverage)->toBe($expectedValue); +})->with([ + [0, 0], + [0.5, 0.5], + [1.0, 1.0], + [32.51, 32.5], + [32.12312321312312, 32.1], + [32.53333333333333, 32.5], + [32.57777771232132, 32.5], + [100.0, 100.0], +]); diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index 313f8208..036f51d7 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -16,7 +16,7 @@ test('parallel', function () use ($run) { expect($run('--exclude-group=integration')) - ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 24 skipped, 1134 passed (2712 assertions)') + ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 24 skipped, 1142 passed (2720 assertions)') ->toContain('Parallel: 3 processes'); })->skipOnWindows();