芝麻web文件管理V1.00
编辑当前文件:/home2/sdektunc/xmintal-back/vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/File.php
* * 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 SebastianBergmann\CodeCoverage\Node\File as FileNode; use SebastianBergmann\CodeCoverage\Util; /** * Renders a file node. */ final class File extends Renderer { /** * @var int */ private $htmlSpecialCharsFlags = \ENT_COMPAT | \ENT_HTML401 | \ENT_SUBSTITUTE; /** * @throws \RuntimeException */ public function render(FileNode $node, string $file): void { $template = new \Text_Template($this->templatePath . 'file.html', '{{', '}}'); $template->setVar( [ 'items' => $this->renderItems($node), 'lines' => $this->renderSource($node), ] ); $this->setCommonTemplateVariables($template, $node); $template->renderTo($file); } protected function renderItems(FileNode $node): string { $template = new \Text_Template($this->templatePath . 'file_item.html', '{{', '}}'); $methodItemTemplate = new \Text_Template( $this->templatePath . 'method_item.html', '{{', '}}' ); $items = $this->renderItemTemplate( $template, [ 'name' => 'Total', 'numClasses' => $node->getNumClassesAndTraits(), 'numTestedClasses' => $node->getNumTestedClassesAndTraits(), 'numMethods' => $node->getNumFunctionsAndMethods(), 'numTestedMethods' => $node->getNumTestedFunctionsAndMethods(), 'linesExecutedPercent' => $node->getLineExecutedPercent(false), 'linesExecutedPercentAsString' => $node->getLineExecutedPercent(), 'numExecutedLines' => $node->getNumExecutedLines(), 'numExecutableLines' => $node->getNumExecutableLines(), 'testedMethodsPercent' => $node->getTestedFunctionsAndMethodsPercent(false), 'testedMethodsPercentAsString' => $node->getTestedFunctionsAndMethodsPercent(), 'testedClassesPercent' => $node->getTestedClassesAndTraitsPercent(false), 'testedClassesPercentAsString' => $node->getTestedClassesAndTraitsPercent(), 'crap' => '
CRAP
', ] ); $items .= $this->renderFunctionItems( $node->getFunctions(), $methodItemTemplate ); $items .= $this->renderTraitOrClassItems( $node->getTraits(), $template, $methodItemTemplate ); $items .= $this->renderTraitOrClassItems( $node->getClasses(), $template, $methodItemTemplate ); return $items; } protected function renderTraitOrClassItems(array $items, \Text_Template $template, \Text_Template $methodItemTemplate): string { $buffer = ''; if (empty($items)) { return $buffer; } foreach ($items as $name => $item) { $numMethods = 0; $numTestedMethods = 0; foreach ($item['methods'] as $method) { if ($method['executableLines'] > 0) { $numMethods++; if ($method['executedLines'] === $method['executableLines']) { $numTestedMethods++; } } } if ($item['executableLines'] > 0) { $numClasses = 1; $numTestedClasses = $numTestedMethods == $numMethods ? 1 : 0; $linesExecutedPercentAsString = Util::percent( $item['executedLines'], $item['executableLines'], true ); } else { $numClasses = 'n/a'; $numTestedClasses = 'n/a'; $linesExecutedPercentAsString = 'n/a'; } $buffer .= $this->renderItemTemplate( $template, [ 'name' => $this->abbreviateClassName($name), 'numClasses' => $numClasses, 'numTestedClasses' => $numTestedClasses, 'numMethods' => $numMethods, 'numTestedMethods' => $numTestedMethods, 'linesExecutedPercent' => Util::percent( $item['executedLines'], $item['executableLines'], false ), 'linesExecutedPercentAsString' => $linesExecutedPercentAsString, 'numExecutedLines' => $item['executedLines'], 'numExecutableLines' => $item['executableLines'], 'testedMethodsPercent' => Util::percent( $numTestedMethods, $numMethods ), 'testedMethodsPercentAsString' => Util::percent( $numTestedMethods, $numMethods, true ), 'testedClassesPercent' => Util::percent( $numTestedMethods == $numMethods ? 1 : 0, 1 ), 'testedClassesPercentAsString' => Util::percent( $numTestedMethods == $numMethods ? 1 : 0, 1, true ), 'crap' => $item['crap'], ] ); foreach ($item['methods'] as $method) { $buffer .= $this->renderFunctionOrMethodItem( $methodItemTemplate, $method, ' ' ); } } return $buffer; } protected function renderFunctionItems(array $functions, \Text_Template $template): string { if (empty($functions)) { return ''; } $buffer = ''; foreach ($functions as $function) { $buffer .= $this->renderFunctionOrMethodItem( $template, $function ); } return $buffer; } protected function renderFunctionOrMethodItem(\Text_Template $template, array $item, string $indent = ''): string { $numMethods = 0; $numTestedMethods = 0; if ($item['executableLines'] > 0) { $numMethods = 1; if ($item['executedLines'] === $item['executableLines']) { $numTestedMethods = 1; } } return $this->renderItemTemplate( $template, [ 'name' => \sprintf( '%s
%s
', $indent, $item['startLine'], \htmlspecialchars($item['signature'], $this->htmlSpecialCharsFlags), $item['functionName'] ?? $item['methodName'] ), 'numMethods' => $numMethods, 'numTestedMethods' => $numTestedMethods, 'linesExecutedPercent' => Util::percent( $item['executedLines'], $item['executableLines'] ), 'linesExecutedPercentAsString' => Util::percent( $item['executedLines'], $item['executableLines'], true ), 'numExecutedLines' => $item['executedLines'], 'numExecutableLines' => $item['executableLines'], 'testedMethodsPercent' => Util::percent( $numTestedMethods, 1 ), 'testedMethodsPercentAsString' => Util::percent( $numTestedMethods, 1, true ), 'crap' => $item['crap'], ] ); } protected function renderSource(FileNode $node): string { $coverageData = $node->getCoverageData(); $testData = $node->getTestData(); $codeLines = $this->loadFile($node->getPath()); $lines = ''; $i = 1; foreach ($codeLines as $line) { $trClass = ''; $popoverContent = ''; $popoverTitle = ''; if (\array_key_exists($i, $coverageData)) { $numTests = ($coverageData[$i] ? \count($coverageData[$i]) : 0); if ($coverageData[$i] === null) { $trClass = ' class="warning"'; } elseif ($numTests == 0) { $trClass = ' class="danger"'; } else { $lineCss = 'covered-by-large-tests'; $popoverContent = '
'; if ($numTests > 1) { $popoverTitle = $numTests . ' tests cover line ' . $i; } else { $popoverTitle = '1 test covers line ' . $i; } foreach ($coverageData[$i] as $test) { if ($lineCss == 'covered-by-large-tests' && $testData[$test]['size'] == 'medium') { $lineCss = 'covered-by-medium-tests'; } elseif ($testData[$test]['size'] == 'small') { $lineCss = 'covered-by-small-tests'; } switch ($testData[$test]['status']) { case 0: switch ($testData[$test]['size']) { case 'small': $testCSS = ' class="covered-by-small-tests"'; break; case 'medium': $testCSS = ' class="covered-by-medium-tests"'; break; default: $testCSS = ' class="covered-by-large-tests"'; break; } break; case 1: case 2: $testCSS = ' class="warning"'; break; case 3: $testCSS = ' class="danger"'; break; case 4: $testCSS = ' class="danger"'; break; default: $testCSS = ''; } $popoverContent .= \sprintf( '
%s
', $testCSS, \htmlspecialchars($test, $this->htmlSpecialCharsFlags) ); } $popoverContent .= '
'; $trClass = ' class="' . $lineCss . ' popin"'; } } $popover = ''; if (!empty($popoverTitle)) { $popover = \sprintf( ' data-title="%s" data-content="%s" data-placement="top" data-html="true"', $popoverTitle, \htmlspecialchars($popoverContent, $this->htmlSpecialCharsFlags) ); } $lines .= \sprintf( '
%d
%s
' . "\n", $trClass, $popover, $i, $i, $i, $line ); $i++; } return $lines; } /** * @param string $file */ protected function loadFile($file): array { $buffer = \file_get_contents($file); $tokens = \token_get_all($buffer); $result = ['']; $i = 0; $stringFlag = false; $fileEndsWithNewLine = \substr($buffer, -1) == "\n"; unset($buffer); foreach ($tokens as $j => $token) { if (\is_string($token)) { if ($token === '"' && $tokens[$j - 1] !== '\\') { $result[$i] .= \sprintf( '
%s
', \htmlspecialchars($token, $this->htmlSpecialCharsFlags) ); $stringFlag = !$stringFlag; } else { $result[$i] .= \sprintf( '
%s
', \htmlspecialchars($token, $this->htmlSpecialCharsFlags) ); } continue; } [$token, $value] = $token; $value = \str_replace( ["\t", ' '], [' ', ' '], \htmlspecialchars($value, $this->htmlSpecialCharsFlags) ); if ($value === "\n") { $result[++$i] = ''; } else { $lines = \explode("\n", $value); foreach ($lines as $jj => $line) { $line = \trim($line); if ($line !== '') { if ($stringFlag) { $colour = 'string'; } else { switch ($token) { case \T_INLINE_HTML: $colour = 'html'; break; case \T_COMMENT: case \T_DOC_COMMENT: $colour = 'comment'; break; case \T_ABSTRACT: case \T_ARRAY: case \T_AS: case \T_BREAK: case \T_CALLABLE: case \T_CASE: case \T_CATCH: case \T_CLASS: case \T_CLONE: case \T_CONTINUE: case \T_DEFAULT: case \T_ECHO: case \T_ELSE: case \T_ELSEIF: case \T_EMPTY: case \T_ENDDECLARE: case \T_ENDFOR: case \T_ENDFOREACH: case \T_ENDIF: case \T_ENDSWITCH: case \T_ENDWHILE: case \T_EXIT: case \T_EXTENDS: case \T_FINAL: case \T_FINALLY: case \T_FOREACH: case \T_FUNCTION: case \T_GLOBAL: case \T_IF: case \T_IMPLEMENTS: case \T_INCLUDE: case \T_INCLUDE_ONCE: case \T_INSTANCEOF: case \T_INSTEADOF: case \T_INTERFACE: case \T_ISSET: case \T_LOGICAL_AND: case \T_LOGICAL_OR: case \T_LOGICAL_XOR: case \T_NAMESPACE: case \T_NEW: case \T_PRIVATE: case \T_PROTECTED: case \T_PUBLIC: case \T_REQUIRE: case \T_REQUIRE_ONCE: case \T_RETURN: case \T_STATIC: case \T_THROW: case \T_TRAIT: case \T_TRY: case \T_UNSET: case \T_USE: case \T_VAR: case \T_WHILE: case \T_YIELD: $colour = 'keyword'; break; default: $colour = 'default'; } } $result[$i] .= \sprintf( '
%s
', $colour, $line ); } if (isset($lines[$jj + 1])) { $result[++$i] = ''; } } } } if ($fileEndsWithNewLine) { unset($result[\count($result) - 1]); } return $result; } private function abbreviateClassName(string $className): string { $tmp = \explode('\\', $className); if (\count($tmp) > 1) { $className = \sprintf( '
%s
', $className, \array_pop($tmp) ); } return $className; } }