summaryrefslogtreecommitdiff
path: root/vendor/phpunit/php-code-coverage/src/Report/Text.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/phpunit/php-code-coverage/src/Report/Text.php')
-rw-r--r--vendor/phpunit/php-code-coverage/src/Report/Text.php341
1 files changed, 341 insertions, 0 deletions
diff --git a/vendor/phpunit/php-code-coverage/src/Report/Text.php b/vendor/phpunit/php-code-coverage/src/Report/Text.php
new file mode 100644
index 000000000..755c2dd48
--- /dev/null
+++ b/vendor/phpunit/php-code-coverage/src/Report/Text.php
@@ -0,0 +1,341 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of phpunit/php-code-coverage.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\CodeCoverage\Report;
+
+use const PHP_EOL;
+use function array_map;
+use function date;
+use function ksort;
+use function max;
+use function sprintf;
+use function str_pad;
+use function strlen;
+use SebastianBergmann\CodeCoverage\CodeCoverage;
+use SebastianBergmann\CodeCoverage\Node\File;
+use SebastianBergmann\CodeCoverage\Util\Percentage;
+
+final class Text
+{
+ /**
+ * @var string
+ */
+ private const COLOR_GREEN = "\x1b[30;42m";
+
+ /**
+ * @var string
+ */
+ private const COLOR_YELLOW = "\x1b[30;43m";
+
+ /**
+ * @var string
+ */
+ private const COLOR_RED = "\x1b[37;41m";
+
+ /**
+ * @var string
+ */
+ private const COLOR_HEADER = "\x1b[1;37;40m";
+
+ /**
+ * @var string
+ */
+ private const COLOR_RESET = "\x1b[0m";
+
+ /**
+ * @var string
+ */
+ private const COLOR_EOL = "\x1b[2K";
+
+ /**
+ * @var int
+ */
+ private $lowUpperBound;
+
+ /**
+ * @var int
+ */
+ private $highLowerBound;
+
+ /**
+ * @var bool
+ */
+ private $showUncoveredFiles;
+
+ /**
+ * @var bool
+ */
+ private $showOnlySummary;
+
+ public function __construct(int $lowUpperBound = 50, int $highLowerBound = 90, bool $showUncoveredFiles = false, bool $showOnlySummary = false)
+ {
+ $this->lowUpperBound = $lowUpperBound;
+ $this->highLowerBound = $highLowerBound;
+ $this->showUncoveredFiles = $showUncoveredFiles;
+ $this->showOnlySummary = $showOnlySummary;
+ }
+
+ public function process(CodeCoverage $coverage, bool $showColors = false): string
+ {
+ $hasBranchCoverage = !empty($coverage->getData(true)->functionCoverage());
+
+ $output = PHP_EOL . PHP_EOL;
+ $report = $coverage->getReport();
+
+ $colors = [
+ 'header' => '',
+ 'classes' => '',
+ 'methods' => '',
+ 'lines' => '',
+ 'branches' => '',
+ 'paths' => '',
+ 'reset' => '',
+ 'eol' => '',
+ ];
+
+ if ($showColors) {
+ $colors['classes'] = $this->coverageColor(
+ $report->numberOfTestedClassesAndTraits(),
+ $report->numberOfClassesAndTraits()
+ );
+
+ $colors['methods'] = $this->coverageColor(
+ $report->numberOfTestedMethods(),
+ $report->numberOfMethods()
+ );
+
+ $colors['lines'] = $this->coverageColor(
+ $report->numberOfExecutedLines(),
+ $report->numberOfExecutableLines()
+ );
+
+ $colors['branches'] = $this->coverageColor(
+ $report->numberOfExecutedBranches(),
+ $report->numberOfExecutableBranches()
+ );
+
+ $colors['paths'] = $this->coverageColor(
+ $report->numberOfExecutedPaths(),
+ $report->numberOfExecutablePaths()
+ );
+
+ $colors['reset'] = self::COLOR_RESET;
+ $colors['header'] = self::COLOR_HEADER;
+ $colors['eol'] = self::COLOR_EOL;
+ }
+
+ $classes = sprintf(
+ ' Classes: %6s (%d/%d)',
+ Percentage::fromFractionAndTotal(
+ $report->numberOfTestedClassesAndTraits(),
+ $report->numberOfClassesAndTraits()
+ )->asString(),
+ $report->numberOfTestedClassesAndTraits(),
+ $report->numberOfClassesAndTraits()
+ );
+
+ $methods = sprintf(
+ ' Methods: %6s (%d/%d)',
+ Percentage::fromFractionAndTotal(
+ $report->numberOfTestedMethods(),
+ $report->numberOfMethods(),
+ )->asString(),
+ $report->numberOfTestedMethods(),
+ $report->numberOfMethods()
+ );
+
+ $paths = '';
+ $branches = '';
+
+ if ($hasBranchCoverage) {
+ $paths = sprintf(
+ ' Paths: %6s (%d/%d)',
+ Percentage::fromFractionAndTotal(
+ $report->numberOfExecutedPaths(),
+ $report->numberOfExecutablePaths(),
+ )->asString(),
+ $report->numberOfExecutedPaths(),
+ $report->numberOfExecutablePaths()
+ );
+
+ $branches = sprintf(
+ ' Branches: %6s (%d/%d)',
+ Percentage::fromFractionAndTotal(
+ $report->numberOfExecutedBranches(),
+ $report->numberOfExecutableBranches(),
+ )->asString(),
+ $report->numberOfExecutedBranches(),
+ $report->numberOfExecutableBranches()
+ );
+ }
+
+ $lines = sprintf(
+ ' Lines: %6s (%d/%d)',
+ Percentage::fromFractionAndTotal(
+ $report->numberOfExecutedLines(),
+ $report->numberOfExecutableLines(),
+ )->asString(),
+ $report->numberOfExecutedLines(),
+ $report->numberOfExecutableLines()
+ );
+
+ $padding = max(array_map('strlen', [$classes, $methods, $lines]));
+
+ if ($this->showOnlySummary) {
+ $title = 'Code Coverage Report Summary:';
+ $padding = max($padding, strlen($title));
+
+ $output .= $this->format($colors['header'], $padding, $title);
+ } else {
+ $date = date(' Y-m-d H:i:s');
+ $title = 'Code Coverage Report:';
+
+ $output .= $this->format($colors['header'], $padding, $title);
+ $output .= $this->format($colors['header'], $padding, $date);
+ $output .= $this->format($colors['header'], $padding, '');
+ $output .= $this->format($colors['header'], $padding, ' Summary:');
+ }
+
+ $output .= $this->format($colors['classes'], $padding, $classes);
+ $output .= $this->format($colors['methods'], $padding, $methods);
+
+ if ($hasBranchCoverage) {
+ $output .= $this->format($colors['paths'], $padding, $paths);
+ $output .= $this->format($colors['branches'], $padding, $branches);
+ }
+ $output .= $this->format($colors['lines'], $padding, $lines);
+
+ if ($this->showOnlySummary) {
+ return $output . PHP_EOL;
+ }
+
+ $classCoverage = [];
+
+ foreach ($report as $item) {
+ if (!$item instanceof File) {
+ continue;
+ }
+
+ $classes = $item->classesAndTraits();
+
+ foreach ($classes as $className => $class) {
+ $classExecutableLines = 0;
+ $classExecutedLines = 0;
+ $classExecutableBranches = 0;
+ $classExecutedBranches = 0;
+ $classExecutablePaths = 0;
+ $classExecutedPaths = 0;
+ $coveredMethods = 0;
+ $classMethods = 0;
+
+ foreach ($class['methods'] as $method) {
+ if ($method['executableLines'] == 0) {
+ continue;
+ }
+
+ $classMethods++;
+ $classExecutableLines += $method['executableLines'];
+ $classExecutedLines += $method['executedLines'];
+ $classExecutableBranches += $method['executableBranches'];
+ $classExecutedBranches += $method['executedBranches'];
+ $classExecutablePaths += $method['executablePaths'];
+ $classExecutedPaths += $method['executedPaths'];
+
+ if ($method['coverage'] == 100) {
+ $coveredMethods++;
+ }
+ }
+
+ $classCoverage[$className] = [
+ 'namespace' => $class['namespace'],
+ 'className' => $className,
+ 'methodsCovered' => $coveredMethods,
+ 'methodCount' => $classMethods,
+ 'statementsCovered' => $classExecutedLines,
+ 'statementCount' => $classExecutableLines,
+ 'branchesCovered' => $classExecutedBranches,
+ 'branchesCount' => $classExecutableBranches,
+ 'pathsCovered' => $classExecutedPaths,
+ 'pathsCount' => $classExecutablePaths,
+ ];
+ }
+ }
+
+ ksort($classCoverage);
+
+ $methodColor = '';
+ $pathsColor = '';
+ $branchesColor = '';
+ $linesColor = '';
+ $resetColor = '';
+
+ foreach ($classCoverage as $fullQualifiedPath => $classInfo) {
+ if ($this->showUncoveredFiles || $classInfo['statementsCovered'] != 0) {
+ if ($showColors) {
+ $methodColor = $this->coverageColor($classInfo['methodsCovered'], $classInfo['methodCount']);
+ $pathsColor = $this->coverageColor($classInfo['pathsCovered'], $classInfo['pathsCount']);
+ $branchesColor = $this->coverageColor($classInfo['branchesCovered'], $classInfo['branchesCount']);
+ $linesColor = $this->coverageColor($classInfo['statementsCovered'], $classInfo['statementCount']);
+ $resetColor = $colors['reset'];
+ }
+
+ $output .= PHP_EOL . $fullQualifiedPath . PHP_EOL
+ . ' ' . $methodColor . 'Methods: ' . $this->printCoverageCounts($classInfo['methodsCovered'], $classInfo['methodCount'], 2) . $resetColor . ' ';
+
+ if ($hasBranchCoverage) {
+ $output .= ' ' . $pathsColor . 'Paths: ' . $this->printCoverageCounts($classInfo['pathsCovered'], $classInfo['pathsCount'], 3) . $resetColor . ' '
+ . ' ' . $branchesColor . 'Branches: ' . $this->printCoverageCounts($classInfo['branchesCovered'], $classInfo['branchesCount'], 3) . $resetColor . ' ';
+ }
+ $output .= ' ' . $linesColor . 'Lines: ' . $this->printCoverageCounts($classInfo['statementsCovered'], $classInfo['statementCount'], 3) . $resetColor;
+ }
+ }
+
+ return $output . PHP_EOL;
+ }
+
+ private function coverageColor(int $numberOfCoveredElements, int $totalNumberOfElements): string
+ {
+ $coverage = Percentage::fromFractionAndTotal(
+ $numberOfCoveredElements,
+ $totalNumberOfElements
+ );
+
+ if ($coverage->asFloat() >= $this->highLowerBound) {
+ return self::COLOR_GREEN;
+ }
+
+ if ($coverage->asFloat() > $this->lowUpperBound) {
+ return self::COLOR_YELLOW;
+ }
+
+ return self::COLOR_RED;
+ }
+
+ private function printCoverageCounts(int $numberOfCoveredElements, int $totalNumberOfElements, int $precision): string
+ {
+ $format = '%' . $precision . 's';
+
+ return Percentage::fromFractionAndTotal(
+ $numberOfCoveredElements,
+ $totalNumberOfElements
+ )->asFixedWidthString() .
+ ' (' . sprintf($format, $numberOfCoveredElements) . '/' .
+ sprintf($format, $totalNumberOfElements) . ')';
+ }
+
+ /**
+ * @param false|string $string
+ */
+ private function format(string $color, int $padding, $string): string
+ {
+ $reset = $color ? self::COLOR_RESET : '';
+
+ return $color . str_pad((string) $string, $padding) . $reset . PHP_EOL;
+ }
+}