From 520798a72090bf29bb2d08574bb485fb7f9e1a63 Mon Sep 17 00:00:00 2001 From: Giacomo Rizzi Date: Fri, 16 May 2025 15:46:47 +0200 Subject: [PATCH 1/2] Fix coverage calculation bug --- src/Node/File.php | 35 ++++++++++++++++++----------------- src/Util/Percentage.php | 2 +- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Node/File.php b/src/Node/File.php index 54ee70b4a..2035df62a 100644 --- a/src/Node/File.php +++ b/src/Node/File.php @@ -299,17 +299,13 @@ public function numberOfMethods(): int foreach ($this->classes as $class) { foreach ($class['methods'] as $method) { - if ($method['executableLines'] > 0) { - $this->numMethods++; - } + $this->numMethods++; } } foreach ($this->traits as $trait) { foreach ($trait['methods'] as $method) { - if ($method['executableLines'] > 0) { - $this->numMethods++; - } + $this->numMethods++; } } } @@ -324,8 +320,7 @@ public function numberOfTestedMethods(): int foreach ($this->classes as $class) { foreach ($class['methods'] as $method) { - if ($method['executableLines'] > 0 && - $method['coverage'] === 100) { + if ($method['coverage'] === 100) { $this->numTestedMethods++; } } @@ -333,8 +328,7 @@ public function numberOfTestedMethods(): int foreach ($this->traits as $trait) { foreach ($trait['methods'] as $method) { - if ($method['executableLines'] > 0 && - $method['coverage'] === 100) { + if ($method['coverage'] === 100) { $this->numTestedMethods++; } } @@ -383,7 +377,9 @@ private function calculateStatistics(array $classes, array $traits, array $funct foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) { if (isset($this->lineCoverageData[$lineNumber])) { foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) { - $codeUnit['executableLines']++; + if (isset($codeUnit['executableLines'])) { + $codeUnit['executableLines']++; + } } unset($codeUnit); @@ -392,7 +388,9 @@ private function calculateStatistics(array $classes, array $traits, array $funct if (count($this->lineCoverageData[$lineNumber]) > 0) { foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) { - $codeUnit['executedLines']++; + if (isset($codeUnit['executedLines'])) { + $codeUnit['executedLines']++; + } } unset($codeUnit); @@ -404,7 +402,7 @@ private function calculateStatistics(array $classes, array $traits, array $funct foreach ($this->traits as &$trait) { foreach ($trait['methods'] as &$method) { - $methodLineCoverage = $method['executableLines'] > 0 ? ($method['executedLines'] / $method['executableLines']) * 100 : 100; + $methodLineCoverage = $method['executableLines'] > 0 ? ($method['executedLines'] / $method['executableLines']) * 100 : 0; $methodBranchCoverage = $method['executableBranches'] > 0 ? ($method['executedBranches'] / $method['executableBranches']) * 100 : 0; $methodPathCoverage = $method['executablePaths'] > 0 ? ($method['executedPaths'] / $method['executablePaths']) * 100 : 0; @@ -416,7 +414,7 @@ private function calculateStatistics(array $classes, array $traits, array $funct unset($method); - $traitLineCoverage = $trait['executableLines'] > 0 ? ($trait['executedLines'] / $trait['executableLines']) * 100 : 100; + $traitLineCoverage = $trait['executableLines'] > 0 ? ($trait['executedLines'] / $trait['executableLines']) * 100 : 0; $traitBranchCoverage = $trait['executableBranches'] > 0 ? ($trait['executedBranches'] / $trait['executableBranches']) * 100 : 0; $traitPathCoverage = $trait['executablePaths'] > 0 ? ($trait['executedPaths'] / $trait['executablePaths']) * 100 : 0; @@ -432,7 +430,7 @@ private function calculateStatistics(array $classes, array $traits, array $funct foreach ($this->classes as &$class) { foreach ($class['methods'] as &$method) { - $methodLineCoverage = $method['executableLines'] > 0 ? ($method['executedLines'] / $method['executableLines']) * 100 : 100; + $methodLineCoverage = $method['executableLines'] > 0 ? ($method['executedLines'] / $method['executableLines']) * 100 : 0; $methodBranchCoverage = $method['executableBranches'] > 0 ? ($method['executedBranches'] / $method['executableBranches']) * 100 : 0; $methodPathCoverage = $method['executablePaths'] > 0 ? ($method['executedPaths'] / $method['executablePaths']) * 100 : 0; @@ -444,7 +442,7 @@ private function calculateStatistics(array $classes, array $traits, array $funct unset($method); - $classLineCoverage = $class['executableLines'] > 0 ? ($class['executedLines'] / $class['executableLines']) * 100 : 100; + $classLineCoverage = $class['executableLines'] > 0 ? ($class['executedLines'] / $class['executableLines']) * 100 : 0; $classBranchCoverage = $class['executableBranches'] > 0 ? ($class['executedBranches'] / $class['executableBranches']) * 100 : 0; $classPathCoverage = $class['executablePaths'] > 0 ? ($class['executedPaths'] / $class['executablePaths']) * 100 : 0; @@ -459,7 +457,7 @@ private function calculateStatistics(array $classes, array $traits, array $funct unset($class); foreach ($this->functions as &$function) { - $functionLineCoverage = $function['executableLines'] > 0 ? ($function['executedLines'] / $function['executableLines']) * 100 : 100; + $functionLineCoverage = $function['executableLines'] > 0 ? ($function['executedLines'] / $function['executableLines']) * 100 : 0; $functionBranchCoverage = $function['executableBranches'] > 0 ? ($function['executedBranches'] / $function['executableBranches']) * 100 : 0; $functionPathCoverage = $function['executablePaths'] > 0 ? ($function['executedPaths'] / $function['executablePaths']) * 100 : 0; @@ -664,6 +662,9 @@ private function newMethod(string $className, Method $method, string $link): arr $key = $className . '->' . $method->name(); + // Initialize executable lines based on the method's body + // (Removed increment and debug output here) + if (isset($this->functionCoverageData[$key]['branches'])) { $methodData['executableBranches'] = count( $this->functionCoverageData[$key]['branches'], diff --git a/src/Util/Percentage.php b/src/Util/Percentage.php index 1de640f80..3d62cdfa0 100644 --- a/src/Util/Percentage.php +++ b/src/Util/Percentage.php @@ -36,7 +36,7 @@ public function asFloat(): float return ($this->fraction / $this->total) * 100; } - return 100.0; + return 0.0; } public function asString(): string From 11f881bedf24e2308af1fdd3397e2c8932e7817f Mon Sep 17 00:00:00 2001 From: Giacomo Rizzi Date: Fri, 16 May 2025 16:47:38 +0200 Subject: [PATCH 2/2] Fix coverage calculation bug for lines --- src/CodeCoverage.php | 5 +++++ src/Node/Builder.php | 1 + src/Node/File.php | 30 ++++++++++++++++++++++++------ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/CodeCoverage.php b/src/CodeCoverage.php index bedc11927..a18380196 100644 --- a/src/CodeCoverage.php +++ b/src/CodeCoverage.php @@ -644,4 +644,9 @@ private function analyser(): FileAnalyser return $this->analyser; } + + public function clearAnalyser(): void + { + $this->analyser = null; + } } diff --git a/src/Node/Builder.php b/src/Node/Builder.php index 19fc3a24d..da0577db9 100644 --- a/src/Node/Builder.php +++ b/src/Node/Builder.php @@ -83,6 +83,7 @@ private function addItems(Directory $root, array $items, array $tests): void $analysisResult->traits(), $analysisResult->functions(), $analysisResult->linesOfCode(), + $analysisResult->executableLines(), ), ); } diff --git a/src/Node/File.php b/src/Node/File.php index 2035df62a..d2b64cd3d 100644 --- a/src/Node/File.php +++ b/src/Node/File.php @@ -140,21 +140,28 @@ final class File extends AbstractNode */ private array $codeUnitsByLine = []; + /** + * @var array + */ + private array $executableLinesGroupedByBranch = []; + /** * @param array> $lineCoverageData * @param array $testData * @param array $classes * @param array $traits * @param array $functions + * @param array $executableLinesGroupedByBranch */ - public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, LinesOfCode $linesOfCode) + public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, LinesOfCode $linesOfCode, array $executableLinesGroupedByBranch) { parent::__construct($name, $parent); - $this->lineCoverageData = $lineCoverageData; + $this->lineCoverageData = $lineCoverageData; $this->functionCoverageData = $functionCoverageData; - $this->testData = $testData; - $this->linesOfCode = $linesOfCode; + $this->testData = $testData; + $this->linesOfCode = $linesOfCode; + $this->executableLinesGroupedByBranch = $executableLinesGroupedByBranch; $this->calculateStatistics($classes, $traits, $functions); } @@ -374,8 +381,11 @@ private function calculateStatistics(array $classes, array $traits, array $funct $this->processTraits($traits); $this->processFunctions($functions); + // Get executable lines from the ExecutableLinesFindingVisitor + $executableLines = $this->executableLinesGroupedByBranch(); + foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) { - if (isset($this->lineCoverageData[$lineNumber])) { + if (isset($executableLines[$lineNumber])) { foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) { if (isset($codeUnit['executableLines'])) { $codeUnit['executableLines']++; @@ -386,7 +396,7 @@ private function calculateStatistics(array $classes, array $traits, array $funct $this->numExecutableLines++; - if (count($this->lineCoverageData[$lineNumber]) > 0) { + if (isset($this->lineCoverageData[$lineNumber]) && count($this->lineCoverageData[$lineNumber] ?? []) > 0) { foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) { if (isset($codeUnit['executedLines'])) { $codeUnit['executedLines']++; @@ -699,4 +709,12 @@ static function (array $path) return $methodData; } + + /** + * @return array + */ + private function executableLinesGroupedByBranch(): array + { + return $this->executableLinesGroupedByBranch; + } }