Chris@14: Chris@14: * Chris@14: * For the full copyright and license information, please view the LICENSE Chris@14: * file that was distributed with this source code. Chris@14: */ Chris@14: Chris@14: namespace SebastianBergmann\CodeCoverage\Report\Html; Chris@14: Chris@14: use SebastianBergmann\CodeCoverage\Node\AbstractNode; Chris@14: use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode; Chris@14: use SebastianBergmann\CodeCoverage\Node\File as FileNode; Chris@14: use SebastianBergmann\CodeCoverage\Version; Chris@14: use SebastianBergmann\Environment\Runtime; Chris@14: Chris@14: /** Chris@14: * Base class for node renderers. Chris@14: */ Chris@14: abstract class Renderer Chris@14: { Chris@14: /** Chris@14: * @var string Chris@14: */ Chris@14: protected $templatePath; Chris@14: Chris@14: /** Chris@14: * @var string Chris@14: */ Chris@14: protected $generator; Chris@14: Chris@14: /** Chris@14: * @var string Chris@14: */ Chris@14: protected $date; Chris@14: Chris@14: /** Chris@14: * @var int Chris@14: */ Chris@14: protected $lowUpperBound; Chris@14: Chris@14: /** Chris@14: * @var int Chris@14: */ Chris@14: protected $highLowerBound; Chris@14: Chris@14: /** Chris@14: * @var string Chris@14: */ Chris@14: protected $version; Chris@14: Chris@14: /** Chris@14: * Constructor. Chris@14: * Chris@14: * @param string $templatePath Chris@14: * @param string $generator Chris@14: * @param string $date Chris@14: * @param int $lowUpperBound Chris@14: * @param int $highLowerBound Chris@14: */ Chris@14: public function __construct($templatePath, $generator, $date, $lowUpperBound, $highLowerBound) Chris@14: { Chris@14: $this->templatePath = $templatePath; Chris@14: $this->generator = $generator; Chris@14: $this->date = $date; Chris@14: $this->lowUpperBound = $lowUpperBound; Chris@14: $this->highLowerBound = $highLowerBound; Chris@14: $this->version = Version::id(); Chris@14: } Chris@14: Chris@14: /** Chris@14: * @param \Text_Template $template Chris@14: * @param array $data Chris@14: * Chris@14: * @return string Chris@14: */ Chris@14: protected function renderItemTemplate(\Text_Template $template, array $data) Chris@14: { Chris@14: $numSeparator = ' / '; Chris@14: Chris@14: if (isset($data['numClasses']) && $data['numClasses'] > 0) { Chris@14: $classesLevel = $this->getColorLevel($data['testedClassesPercent']); Chris@14: Chris@14: $classesNumber = $data['numTestedClasses'] . $numSeparator . Chris@14: $data['numClasses']; Chris@14: Chris@14: $classesBar = $this->getCoverageBar( Chris@14: $data['testedClassesPercent'] Chris@14: ); Chris@14: } else { Chris@14: $classesLevel = ''; Chris@14: $classesNumber = '0' . $numSeparator . '0'; Chris@14: $classesBar = ''; Chris@14: $data['testedClassesPercentAsString'] = 'n/a'; Chris@14: } Chris@14: Chris@14: if ($data['numMethods'] > 0) { Chris@14: $methodsLevel = $this->getColorLevel($data['testedMethodsPercent']); Chris@14: Chris@14: $methodsNumber = $data['numTestedMethods'] . $numSeparator . Chris@14: $data['numMethods']; Chris@14: Chris@14: $methodsBar = $this->getCoverageBar( Chris@14: $data['testedMethodsPercent'] Chris@14: ); Chris@14: } else { Chris@14: $methodsLevel = ''; Chris@14: $methodsNumber = '0' . $numSeparator . '0'; Chris@14: $methodsBar = ''; Chris@14: $data['testedMethodsPercentAsString'] = 'n/a'; Chris@14: } Chris@14: Chris@14: if ($data['numExecutableLines'] > 0) { Chris@14: $linesLevel = $this->getColorLevel($data['linesExecutedPercent']); Chris@14: Chris@14: $linesNumber = $data['numExecutedLines'] . $numSeparator . Chris@14: $data['numExecutableLines']; Chris@14: Chris@14: $linesBar = $this->getCoverageBar( Chris@14: $data['linesExecutedPercent'] Chris@14: ); Chris@14: } else { Chris@14: $linesLevel = ''; Chris@14: $linesNumber = '0' . $numSeparator . '0'; Chris@14: $linesBar = ''; Chris@14: $data['linesExecutedPercentAsString'] = 'n/a'; Chris@14: } Chris@14: Chris@14: $template->setVar( Chris@14: [ Chris@14: 'icon' => isset($data['icon']) ? $data['icon'] : '', Chris@14: 'crap' => isset($data['crap']) ? $data['crap'] : '', Chris@14: 'name' => $data['name'], Chris@14: 'lines_bar' => $linesBar, Chris@14: 'lines_executed_percent' => $data['linesExecutedPercentAsString'], Chris@14: 'lines_level' => $linesLevel, Chris@14: 'lines_number' => $linesNumber, Chris@14: 'methods_bar' => $methodsBar, Chris@14: 'methods_tested_percent' => $data['testedMethodsPercentAsString'], Chris@14: 'methods_level' => $methodsLevel, Chris@14: 'methods_number' => $methodsNumber, Chris@14: 'classes_bar' => $classesBar, Chris@14: 'classes_tested_percent' => isset($data['testedClassesPercentAsString']) ? $data['testedClassesPercentAsString'] : '', Chris@14: 'classes_level' => $classesLevel, Chris@14: 'classes_number' => $classesNumber Chris@14: ] Chris@14: ); Chris@14: Chris@14: return $template->render(); Chris@14: } Chris@14: Chris@14: /** Chris@14: * @param \Text_Template $template Chris@14: * @param AbstractNode $node Chris@14: */ Chris@14: protected function setCommonTemplateVariables(\Text_Template $template, AbstractNode $node) Chris@14: { Chris@14: $template->setVar( Chris@14: [ Chris@14: 'id' => $node->getId(), Chris@14: 'full_path' => $node->getPath(), Chris@14: 'path_to_root' => $this->getPathToRoot($node), Chris@14: 'breadcrumbs' => $this->getBreadcrumbs($node), Chris@14: 'date' => $this->date, Chris@14: 'version' => $this->version, Chris@14: 'runtime' => $this->getRuntimeString(), Chris@14: 'generator' => $this->generator, Chris@14: 'low_upper_bound' => $this->lowUpperBound, Chris@14: 'high_lower_bound' => $this->highLowerBound Chris@14: ] Chris@14: ); Chris@14: } Chris@14: Chris@14: protected function getBreadcrumbs(AbstractNode $node) Chris@14: { Chris@14: $breadcrumbs = ''; Chris@14: $path = $node->getPathAsArray(); Chris@14: $pathToRoot = []; Chris@14: $max = \count($path); Chris@14: Chris@14: if ($node instanceof FileNode) { Chris@14: $max--; Chris@14: } Chris@14: Chris@14: for ($i = 0; $i < $max; $i++) { Chris@14: $pathToRoot[] = \str_repeat('../', $i); Chris@14: } Chris@14: Chris@14: foreach ($path as $step) { Chris@14: if ($step !== $node) { Chris@14: $breadcrumbs .= $this->getInactiveBreadcrumb( Chris@14: $step, Chris@14: \array_pop($pathToRoot) Chris@14: ); Chris@14: } else { Chris@14: $breadcrumbs .= $this->getActiveBreadcrumb($step); Chris@14: } Chris@14: } Chris@14: Chris@14: return $breadcrumbs; Chris@14: } Chris@14: Chris@14: protected function getActiveBreadcrumb(AbstractNode $node) Chris@14: { Chris@14: $buffer = \sprintf( Chris@14: '
  • %s
  • ' . "\n", Chris@14: $node->getName() Chris@14: ); Chris@14: Chris@14: if ($node instanceof DirectoryNode) { Chris@14: $buffer .= '
  • (Dashboard)
  • ' . "\n"; Chris@14: } Chris@14: Chris@14: return $buffer; Chris@14: } Chris@14: Chris@14: protected function getInactiveBreadcrumb(AbstractNode $node, $pathToRoot) Chris@14: { Chris@14: return \sprintf( Chris@14: '
  • %s
  • ' . "\n", Chris@14: $pathToRoot, Chris@14: $node->getName() Chris@14: ); Chris@14: } Chris@14: Chris@14: protected function getPathToRoot(AbstractNode $node) Chris@14: { Chris@14: $id = $node->getId(); Chris@14: $depth = \substr_count($id, '/'); Chris@14: Chris@14: if ($id != 'index' && Chris@14: $node instanceof DirectoryNode) { Chris@14: $depth++; Chris@14: } Chris@14: Chris@14: return \str_repeat('../', $depth); Chris@14: } Chris@14: Chris@14: protected function getCoverageBar($percent) Chris@14: { Chris@14: $level = $this->getColorLevel($percent); Chris@14: Chris@14: $template = new \Text_Template( Chris@14: $this->templatePath . 'coverage_bar.html', Chris@14: '{{', Chris@14: '}}' Chris@14: ); Chris@14: Chris@14: $template->setVar(['level' => $level, 'percent' => \sprintf('%.2F', $percent)]); Chris@14: Chris@14: return $template->render(); Chris@14: } Chris@14: Chris@14: /** Chris@14: * @param int $percent Chris@14: * Chris@14: * @return string Chris@14: */ Chris@14: protected function getColorLevel($percent) Chris@14: { Chris@14: if ($percent <= $this->lowUpperBound) { Chris@14: return 'danger'; Chris@14: } elseif ($percent > $this->lowUpperBound && Chris@14: $percent < $this->highLowerBound) { Chris@14: return 'warning'; Chris@14: } else { Chris@14: return 'success'; Chris@14: } Chris@14: } Chris@14: Chris@14: /** Chris@14: * @return string Chris@14: */ Chris@14: private function getRuntimeString() Chris@14: { Chris@14: $runtime = new Runtime; Chris@14: Chris@14: $buffer = \sprintf( Chris@14: '%s %s', Chris@14: $runtime->getVendorUrl(), Chris@14: $runtime->getName(), Chris@14: $runtime->getVersion() Chris@14: ); Chris@14: Chris@14: if ($runtime->hasXdebug() && !$runtime->hasPHPDBGCodeCoverage()) { Chris@14: $buffer .= \sprintf( Chris@14: ' with Xdebug %s', Chris@14: \phpversion('xdebug') Chris@14: ); Chris@14: } Chris@14: Chris@14: return $buffer; Chris@14: } Chris@14: }