From 47fd3ed4916cb9baa29764bde75bcfaaa64f3153 Mon Sep 17 00:00:00 2001 From: Joe Rieger Date: Thu, 13 Jun 2019 16:59:44 -0400 Subject: [PATCH] Make Xml reporter work with paths and branches --- src/Report/Clover.php | 2 +- src/Report/Crap4j.php | 3 ++- src/Report/Html/Facade.php | 13 ++-------- src/Report/PHP.php | 3 ++- src/Report/Reporter.php | 23 +++++++++++++++++ src/Report/Text.php | 13 ++-------- src/Report/Xml/Facade.php | 53 +++++++++++++++++++++++++++++++++++--- src/Report/Xml/File.php | 12 ++++++++- src/Report/Xml/Method.php | 23 ++++++++++++++--- src/Report/Xml/Node.php | 22 +++++++++++++--- src/Report/Xml/Totals.php | 53 +++++++++++++++++++++++++++++++++++++- 11 files changed, 183 insertions(+), 37 deletions(-) create mode 100644 src/Report/Reporter.php diff --git a/src/Report/Clover.php b/src/Report/Clover.php index e0f893ce2..6333ace12 100644 --- a/src/Report/Clover.php +++ b/src/Report/Clover.php @@ -16,7 +16,7 @@ /** * Generates a Clover XML logfile from a code coverage object. */ -final class Clover +final class Clover extends Reporter { /** * @throws \RuntimeException diff --git a/src/Report/Crap4j.php b/src/Report/Crap4j.php index 6713be0c8..6d6be8e09 100644 --- a/src/Report/Crap4j.php +++ b/src/Report/Crap4j.php @@ -12,8 +12,9 @@ use SebastianBergmann\CodeCoverage\CodeCoverage; use SebastianBergmann\CodeCoverage\Node\File; use SebastianBergmann\CodeCoverage\RuntimeException; +use SebastianBergmann\CodeCoverage\Report\Reporter; -final class Crap4j +final class Crap4j extends Reporter { /** * @var int diff --git a/src/Report/Html/Facade.php b/src/Report/Html/Facade.php index 5120fa72b..6d82f18aa 100644 --- a/src/Report/Html/Facade.php +++ b/src/Report/Html/Facade.php @@ -11,12 +11,13 @@ use SebastianBergmann\CodeCoverage\CodeCoverage; use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode; +use SebastianBergmann\CodeCoverage\Report\Reporter; use SebastianBergmann\CodeCoverage\RuntimeException; /** * Generates an HTML report from a code coverage object. */ -final class Facade +final class Facade extends Reporter { /** * @var string @@ -38,11 +39,6 @@ final class Facade */ private $highLowerBound; - /** - * @var bool - */ - private $determineBranchCoverage = false; - public function __construct(int $lowUpperBound = 50, int $highLowerBound = 90, string $generator = '') { $this->generator = $generator; @@ -121,11 +117,6 @@ public function process(CodeCoverage $coverage, string $target): void $this->copyFiles($target); } - public function setDetermineBranchCoverage(bool $determineBranchCoverage): void - { - $this->determineBranchCoverage = $determineBranchCoverage; - } - /** * @throws RuntimeException */ diff --git a/src/Report/PHP.php b/src/Report/PHP.php index 73e2f4ddf..8a74afff7 100644 --- a/src/Report/PHP.php +++ b/src/Report/PHP.php @@ -11,11 +11,12 @@ use SebastianBergmann\CodeCoverage\CodeCoverage; use SebastianBergmann\CodeCoverage\RuntimeException; +use SebastianBergmann\CodeCoverage\Report\Reporter; /** * Uses var_export() to write a SebastianBergmann\CodeCoverage\CodeCoverage object to a file. */ -final class PHP +final class PHP extends Reporter { /** * @throws \SebastianBergmann\CodeCoverage\RuntimeException diff --git a/src/Report/Reporter.php b/src/Report/Reporter.php new file mode 100644 index 000000000..b2efb1134 --- /dev/null +++ b/src/Report/Reporter.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SebastianBergmann\CodeCoverage\Report; + +abstract class Reporter +{ + /** + * @var bool + */ + protected $determineBranchCoverage = false; + + public function setDetermineBranchCoverage(bool $determineBranchCoverage): void + { + $this->determineBranchCoverage = $determineBranchCoverage; + } +} diff --git a/src/Report/Text.php b/src/Report/Text.php index 1a35cbe0b..7f0d641a1 100644 --- a/src/Report/Text.php +++ b/src/Report/Text.php @@ -12,13 +12,14 @@ use SebastianBergmann\CodeCoverage\CodeCoverage; use SebastianBergmann\CodeCoverage\Node\File; use SebastianBergmann\CodeCoverage\Util; +use SebastianBergmann\CodeCoverage\Report\Reporter; /** * Generates human readable output from a code coverage object. * * The output gets put into a text file our written to the CLI. */ -final class Text +final class Text extends Reporter { /** * @var string @@ -70,11 +71,6 @@ final class Text */ private $showOnlySummary; - /** - * @var bool - */ - private $determineBranchCoverage = false; - public function __construct(int $lowUpperBound = 50, int $highLowerBound = 90, bool $showUncoveredFiles = false, bool $showOnlySummary = false) { $this->lowUpperBound = $lowUpperBound; @@ -350,11 +346,6 @@ public function process(CodeCoverage $coverage, bool $showColors = false): strin return $output . \PHP_EOL; } - public function setDetermineBranchCoverage(bool $determineBranchCoverage): void - { - $this->determineBranchCoverage = $determineBranchCoverage; - } - private function getCoverageColor(int $numberOfCoveredElements, int $totalNumberOfElements): string { $coverage = Util::percent( diff --git a/src/Report/Xml/Facade.php b/src/Report/Xml/Facade.php index c908a1507..799b79875 100644 --- a/src/Report/Xml/Facade.php +++ b/src/Report/Xml/Facade.php @@ -13,11 +13,12 @@ use SebastianBergmann\CodeCoverage\Node\AbstractNode; use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode; use SebastianBergmann\CodeCoverage\Node\File as FileNode; +use SebastianBergmann\CodeCoverage\Report\Reporter; use SebastianBergmann\CodeCoverage\RuntimeException; use SebastianBergmann\CodeCoverage\Version; use SebastianBergmann\Environment\Runtime; -final class Facade +final class Facade extends Reporter { /** * @var string @@ -56,6 +57,7 @@ public function process(CodeCoverage $coverage, string $target): void $this->project = new Project( $coverage->getReport()->getName() ); + $this->project->setDetermineBranchCoverage($this->determineBranchCoverage); $this->setBuildInformation(); $this->processTests($coverage->getTests()); @@ -135,6 +137,7 @@ private function processFile(FileNode $file, Directory $context): void ); $fileReport = new Report($path); + $fileReport->setDetermineBranchCoverage($this->determineBranchCoverage); $this->setTotals($file, $fileReport->getTotals()); @@ -146,7 +149,13 @@ private function processFile(FileNode $file, Directory $context): void $this->processFunction($function, $fileReport); } - foreach ($file->getCoverageData() as $line => $tests) { + $fileCoverageData = $file->getCoverageData(); + foreach ($fileCoverageData['lines'] as $line => $lineData) { + if ($lineData === null) { + continue; + } + + $tests = $lineData['tests']; if (!\is_array($tests) || \count($tests) === 0) { continue; } @@ -202,6 +211,17 @@ private function processUnit(array $unit, Report $report): void (string) $method['executedLines'], (string) $method['coverage'] ); + + if ($this->determineBranchCoverage) { + $methodObject->setPathTotals( + (string) $method['executablePaths'], + (string) $method['executedPaths'] + ); + $methodObject->setBranchTotals( + (string) $method['executableBranches'], + (string) $method['executedBranches'] + ); + } } } @@ -212,7 +232,22 @@ private function processFunction(array $function, Report $report): void $functionObject->setSignature($function['signature']); $functionObject->setLines((string) $function['startLine']); $functionObject->setCrap($function['crap']); - $functionObject->setTotals((string) $function['executableLines'], (string) $function['executedLines'], (string) $function['coverage']); + $functionObject->setTotals( + (string) $function['executableLines'], + (string) $function['executedLines'], + (string) $function['coverage'] + ); + + if ($this->determineBranchCoverage) { + $functionObject->setPathTotals( + (string) $function['executablePaths'], + (string) $function['executedPaths'] + ); + $functionObject->setBranchTotals( + (string) $function['executableBranches'], + (string) $function['executedBranches'] + ); + } } private function processTests(array $tests): void @@ -259,6 +294,18 @@ private function setTotals(AbstractNode $node, Totals $totals): void $node->getNumFunctions(), $node->getNumTestedFunctions() ); + + if ($this->determineBranchCoverage) { + $totals->setNumPaths( + $node->getNumPaths(), + $node->getNumTestedPaths() + ); + + $totals->setNumBranches( + $node->getNumBranches(), + $node->getNumTestedBranches() + ); + } } private function getTargetDirectory(): string diff --git a/src/Report/Xml/File.php b/src/Report/Xml/File.php index 02af64477..cac8587b2 100644 --- a/src/Report/Xml/File.php +++ b/src/Report/Xml/File.php @@ -21,6 +21,11 @@ class File */ private $contextNode; + /** + * @var bool + */ + private $determineBranchCoverage = false; + public function __construct(\DOMElement $context) { $this->dom = $context->ownerDocument; @@ -40,7 +45,7 @@ public function getTotals(): Totals ); } - return new Totals($totalsContainer); + return new Totals($totalsContainer, $this->determineBranchCoverage); } public function getLineCoverage(string $line): Coverage @@ -69,6 +74,11 @@ public function getLineCoverage(string $line): Coverage return new Coverage($lineNode, $line); } + public function setDetermineBranchCoverage(bool $determineBranchCoverage): void + { + $this->determineBranchCoverage = $determineBranchCoverage; + } + protected function getContextNode(): \DOMElement { return $this->contextNode; diff --git a/src/Report/Xml/Method.php b/src/Report/Xml/Method.php index b6a7f1602..ee8d9fee1 100644 --- a/src/Report/Xml/Method.php +++ b/src/Report/Xml/Method.php @@ -37,13 +37,28 @@ public function setLines(string $start, ?string $end = null): void } } - public function setTotals(string $executable, string $executed, string $coverage): void - { - $this->contextNode->setAttribute('executable', $executable); - $this->contextNode->setAttribute('executed', $executed); + public function setTotals( + string $executableLines, + string $executedLines, + string $coverage + ): void { + $this->contextNode->setAttribute('executable', $executableLines); + $this->contextNode->setAttribute('executed', $executedLines); $this->contextNode->setAttribute('coverage', $coverage); } + public function setPathTotals(string $executablePaths, string $executedPaths): void + { + $this->contextNode->setAttribute('executablePaths', $executablePaths); + $this->contextNode->setAttribute('executedPaths', $executedPaths); + } + + public function setBranchTotals(string $executableBranches, string $executedBranches): void + { + $this->contextNode->setAttribute('executableBranches', $executableBranches); + $this->contextNode->setAttribute('executedBranches', $executedBranches); + } + public function setCrap(string $crap): void { $this->contextNode->setAttribute('crap', $crap); diff --git a/src/Report/Xml/Node.php b/src/Report/Xml/Node.php index d3ba223a5..8610c63cd 100644 --- a/src/Report/Xml/Node.php +++ b/src/Report/Xml/Node.php @@ -21,6 +21,11 @@ abstract class Node */ private $contextNode; + /** + * @var bool + */ + protected $determineBranchCoverage = false; + public function __construct(\DOMElement $context) { $this->setContextNode($context); @@ -44,7 +49,7 @@ public function getTotals(): Totals ); } - return new Totals($totalsContainer); + return new Totals($totalsContainer, $this->determineBranchCoverage); } public function addDirectory(string $name): Directory @@ -57,7 +62,10 @@ public function addDirectory(string $name): Directory $dirNode->setAttribute('name', $name); $this->getContextNode()->appendChild($dirNode); - return new Directory($dirNode); + $directory = new Directory($dirNode); + $directory->setDetermineBranchCoverage($this->determineBranchCoverage); + + return $directory; } public function addFile(string $name, string $href): File @@ -71,7 +79,15 @@ public function addFile(string $name, string $href): File $fileNode->setAttribute('href', $href); $this->getContextNode()->appendChild($fileNode); - return new File($fileNode); + $file = new File($fileNode); + $file->setDetermineBranchCoverage($this->determineBranchCoverage); + + return $file; + } + + public function setDetermineBranchCoverage(bool $determineBranchCoverage): void + { + $this->determineBranchCoverage = $determineBranchCoverage; } protected function setContextNode(\DOMElement $context): void diff --git a/src/Report/Xml/Totals.php b/src/Report/Xml/Totals.php index 019f348cb..c50503188 100644 --- a/src/Report/Xml/Totals.php +++ b/src/Report/Xml/Totals.php @@ -43,7 +43,17 @@ final class Totals */ private $traitsNode; - public function __construct(\DOMElement $container) + /** + * @var null|\DOMElement + */ + private $pathsNode; + + /** + * @var null|\DOMElement + */ + private $branchesNode; + + public function __construct(\DOMElement $container, bool $determineBranchCoverage = false) { $this->container = $container; $dom = $container->ownerDocument; @@ -78,6 +88,19 @@ public function __construct(\DOMElement $container) $container->appendChild($this->functionsNode); $container->appendChild($this->classesNode); $container->appendChild($this->traitsNode); + + if ($determineBranchCoverage) { + $this->pathsNode = $dom->createElementNS( + 'https://schema.phpunit.de/coverage/1.0', + 'paths' + ); + $this->branchesNode = $dom->createElementNS( + 'https://schema.phpunit.de/coverage/1.0', + 'branches' + ); + $container->appendChild($this->pathsNode); + $container->appendChild($this->branchesNode); + } } public function getContainer(): \DOMNode @@ -137,4 +160,32 @@ public function setNumFunctions(int $count, int $tested): void $count === 0 ? '0' : \sprintf('%01.2F', Util::percent($tested, $count)) ); } + + public function setNumPaths(int $count, int $tested): void + { + if ($this->pathsNode === null) { + return; + } + + $this->pathsNode->setAttribute('count', (string) $count); + $this->pathsNode->setAttribute('tested', (string) $tested); + $this->pathsNode->setAttribute( + 'percent', + $count === 0 ? '0' : \sprintf('%01.2F', Util::percent($tested, $count)) + ); + } + + public function setNumBranches(int $count, int $tested): void + { + if ($this->branchesNode === null) { + return; + } + + $this->branchesNode->setAttribute('count', (string) $count); + $this->branchesNode->setAttribute('tested', (string) $tested); + $this->branchesNode->setAttribute( + 'percent', + $count === 0 ? '0' : \sprintf('%01.2F', Util::percent($tested, $count)) + ); + } }