Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php declare(strict_types=1);/** This file is part of phpunit/php-code-coverage.** (c) Sebastian Bergmann <sebastian@phpunit.de>** For the full copyright and license information, please view the LICENSE* file that was distributed with this source code.*/namespace SebastianBergmann\CodeCoverage\Report\Html;use function array_pop;use function count;use function sprintf;use function str_repeat;use function substr_count;use SebastianBergmann\CodeCoverage\Node\AbstractNode;use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;use SebastianBergmann\CodeCoverage\Node\File as FileNode;use SebastianBergmann\CodeCoverage\Version;use SebastianBergmann\Environment\Runtime;use SebastianBergmann\Template\Template;/*** @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage*/abstract class Renderer{/*** @var string*/protected $templatePath;/*** @var string*/protected $generator;/*** @var string*/protected $date;/*** @var int*/protected $lowUpperBound;/*** @var int*/protected $highLowerBound;/*** @var bool*/protected $hasBranchCoverage;/*** @var string*/protected $version;public function __construct(string $templatePath, string $generator, string $date, int $lowUpperBound, int $highLowerBound, bool $hasBranchCoverage){$this->templatePath = $templatePath;$this->generator = $generator;$this->date = $date;$this->lowUpperBound = $lowUpperBound;$this->highLowerBound = $highLowerBound;$this->version = Version::id();$this->hasBranchCoverage = $hasBranchCoverage;}protected function renderItemTemplate(Template $template, array $data): string{$numSeparator = ' / ';if (isset($data['numClasses']) && $data['numClasses'] > 0) {$classesLevel = $this->colorLevel($data['testedClassesPercent']);$classesNumber = $data['numTestedClasses'] . $numSeparator .$data['numClasses'];$classesBar = $this->coverageBar($data['testedClassesPercent']);} else {$classesLevel = '';$classesNumber = '0' . $numSeparator . '0';$classesBar = '';$data['testedClassesPercentAsString'] = 'n/a';}if ($data['numMethods'] > 0) {$methodsLevel = $this->colorLevel($data['testedMethodsPercent']);$methodsNumber = $data['numTestedMethods'] . $numSeparator .$data['numMethods'];$methodsBar = $this->coverageBar($data['testedMethodsPercent']);} else {$methodsLevel = '';$methodsNumber = '0' . $numSeparator . '0';$methodsBar = '';$data['testedMethodsPercentAsString'] = 'n/a';}if ($data['numExecutableLines'] > 0) {$linesLevel = $this->colorLevel($data['linesExecutedPercent']);$linesNumber = $data['numExecutedLines'] . $numSeparator .$data['numExecutableLines'];$linesBar = $this->coverageBar($data['linesExecutedPercent']);} else {$linesLevel = '';$linesNumber = '0' . $numSeparator . '0';$linesBar = '';$data['linesExecutedPercentAsString'] = 'n/a';}if ($data['numExecutablePaths'] > 0) {$pathsLevel = $this->colorLevel($data['pathsExecutedPercent']);$pathsNumber = $data['numExecutedPaths'] . $numSeparator .$data['numExecutablePaths'];$pathsBar = $this->coverageBar($data['pathsExecutedPercent']);} else {$pathsLevel = '';$pathsNumber = '0' . $numSeparator . '0';$pathsBar = '';$data['pathsExecutedPercentAsString'] = 'n/a';}if ($data['numExecutableBranches'] > 0) {$branchesLevel = $this->colorLevel($data['branchesExecutedPercent']);$branchesNumber = $data['numExecutedBranches'] . $numSeparator .$data['numExecutableBranches'];$branchesBar = $this->coverageBar($data['branchesExecutedPercent']);} else {$branchesLevel = '';$branchesNumber = '0' . $numSeparator . '0';$branchesBar = '';$data['branchesExecutedPercentAsString'] = 'n/a';}$template->setVar(['icon' => $data['icon'] ?? '','crap' => $data['crap'] ?? '','name' => $data['name'],'lines_bar' => $linesBar,'lines_executed_percent' => $data['linesExecutedPercentAsString'],'lines_level' => $linesLevel,'lines_number' => $linesNumber,'paths_bar' => $pathsBar,'paths_executed_percent' => $data['pathsExecutedPercentAsString'],'paths_level' => $pathsLevel,'paths_number' => $pathsNumber,'branches_bar' => $branchesBar,'branches_executed_percent' => $data['branchesExecutedPercentAsString'],'branches_level' => $branchesLevel,'branches_number' => $branchesNumber,'methods_bar' => $methodsBar,'methods_tested_percent' => $data['testedMethodsPercentAsString'],'methods_level' => $methodsLevel,'methods_number' => $methodsNumber,'classes_bar' => $classesBar,'classes_tested_percent' => $data['testedClassesPercentAsString'] ?? '','classes_level' => $classesLevel,'classes_number' => $classesNumber,]);return $template->render();}protected function setCommonTemplateVariables(Template $template, AbstractNode $node): void{$template->setVar(['id' => $node->id(),'full_path' => $node->pathAsString(),'path_to_root' => $this->pathToRoot($node),'breadcrumbs' => $this->breadcrumbs($node),'date' => $this->date,'version' => $this->version,'runtime' => $this->runtimeString(),'generator' => $this->generator,'low_upper_bound' => $this->lowUpperBound,'high_lower_bound' => $this->highLowerBound,]);}protected function breadcrumbs(AbstractNode $node): string{$breadcrumbs = '';$path = $node->pathAsArray();$pathToRoot = [];$max = count($path);if ($node instanceof FileNode) {$max--;}for ($i = 0; $i < $max; $i++) {$pathToRoot[] = str_repeat('../', $i);}foreach ($path as $step) {if ($step !== $node) {$breadcrumbs .= $this->inactiveBreadcrumb($step,array_pop($pathToRoot));} else {$breadcrumbs .= $this->activeBreadcrumb($step);}}return $breadcrumbs;}protected function activeBreadcrumb(AbstractNode $node): string{$buffer = sprintf(' <li class="breadcrumb-item active">%s</li>' . "\n",$node->name());if ($node instanceof DirectoryNode) {$buffer .= ' <li class="breadcrumb-item">(<a href="dashboard.html">Dashboard</a>)</li>' . "\n";}return $buffer;}protected function inactiveBreadcrumb(AbstractNode $node, string $pathToRoot): string{return sprintf(' <li class="breadcrumb-item"><a href="%sindex.html">%s</a></li>' . "\n",$pathToRoot,$node->name());}protected function pathToRoot(AbstractNode $node): string{$id = $node->id();$depth = substr_count($id, '/');if ($id !== 'index' &&$node instanceof DirectoryNode) {$depth++;}return str_repeat('../', $depth);}protected function coverageBar(float $percent): string{$level = $this->colorLevel($percent);$templateName = $this->templatePath . ($this->hasBranchCoverage ? 'coverage_bar_branch.html' : 'coverage_bar.html');$template = new Template($templateName,'{{','}}');$template->setVar(['level' => $level, 'percent' => sprintf('%.2F', $percent)]);return $template->render();}protected function colorLevel(float $percent): string{if ($percent <= $this->lowUpperBound) {return 'danger';}if ($percent > $this->lowUpperBound &&$percent < $this->highLowerBound) {return 'warning';}return 'success';}private function runtimeString(): string{$runtime = new Runtime;return sprintf('<a href="%s" target="_top">%s %s</a>',$runtime->getVendorUrl(),$runtime->getName(),$runtime->getVersion());}}