first commit

This commit is contained in:
kicap
2023-07-11 17:28:33 +08:00
commit 8b945c8750
3343 changed files with 975054 additions and 0 deletions

View File

@ -0,0 +1,67 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
use SebastianBergmann\CodeCoverage\RuntimeException;
class Coverage
{
/**
* @var \XMLWriter
*/
private $writer;
/**
* @var \DOMElement
*/
private $contextNode;
/**
* @var bool
*/
private $finalized = false;
public function __construct(\DOMElement $context, $line)
{
$this->contextNode = $context;
$this->writer = new \XMLWriter;
$this->writer->openMemory();
$this->writer->startElementNs(null, $context->nodeName, 'http://schema.phpunit.de/coverage/1.0');
$this->writer->writeAttribute('nr', $line);
}
public function addTest($test)
{
if ($this->finalized) {
throw new RuntimeException('Coverage Report already finalized');
}
$this->writer->startElement('covered');
$this->writer->writeAttribute('by', $test);
$this->writer->endElement();
}
public function finalize()
{
$this->writer->endElement();
$fragment = $this->contextNode->ownerDocument->createDocumentFragment();
$fragment->appendXML($this->writer->outputMemory());
$this->contextNode->parentNode->replaceChild(
$fragment,
$this->contextNode
);
$this->finalized = true;
}
}

View File

@ -0,0 +1,15 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
class Directory extends Node
{
}

View File

@ -0,0 +1,238 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Node\AbstractNode;
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
use SebastianBergmann\CodeCoverage\Node\File as FileNode;
use SebastianBergmann\CodeCoverage\RuntimeException;
class Facade
{
/**
* @var string
*/
private $target;
/**
* @var Project
*/
private $project;
/**
* @param CodeCoverage $coverage
* @param string $target
*
* @throws RuntimeException
*/
public function process(CodeCoverage $coverage, $target)
{
if (substr($target, -1, 1) != DIRECTORY_SEPARATOR) {
$target .= DIRECTORY_SEPARATOR;
}
$this->target = $target;
$this->initTargetDirectory($target);
$report = $coverage->getReport();
$this->project = new Project(
$coverage->getReport()->getName()
);
$this->processTests($coverage->getTests());
$this->processDirectory($report, $this->project);
$index = $this->project->asDom();
$index->formatOutput = true;
$index->preserveWhiteSpace = false;
$index->save($target . '/index.xml');
}
/**
* @param string $directory
*/
private function initTargetDirectory($directory)
{
if (file_exists($directory)) {
if (!is_dir($directory)) {
throw new RuntimeException(
"'$directory' exists but is not a directory."
);
}
if (!is_writable($directory)) {
throw new RuntimeException(
"'$directory' exists but is not writable."
);
}
} elseif (!@mkdir($directory, 0777, true)) {
throw new RuntimeException(
"'$directory' could not be created."
);
}
}
private function processDirectory(DirectoryNode $directory, Node $context)
{
$dirObject = $context->addDirectory($directory->getName());
$this->setTotals($directory, $dirObject->getTotals());
foreach ($directory->getDirectories() as $node) {
$this->processDirectory($node, $dirObject);
}
foreach ($directory->getFiles() as $node) {
$this->processFile($node, $dirObject);
}
}
private function processFile(FileNode $file, Directory $context)
{
$fileObject = $context->addFile(
$file->getName(),
$file->getId() . '.xml'
);
$this->setTotals($file, $fileObject->getTotals());
$fileReport = new Report($file->getName());
$this->setTotals($file, $fileReport->getTotals());
foreach ($file->getClassesAndTraits() as $unit) {
$this->processUnit($unit, $fileReport);
}
foreach ($file->getFunctions() as $function) {
$this->processFunction($function, $fileReport);
}
foreach ($file->getCoverageData() as $line => $tests) {
if (!is_array($tests) || count($tests) == 0) {
continue;
}
$coverage = $fileReport->getLineCoverage($line);
foreach ($tests as $test) {
$coverage->addTest($test);
}
$coverage->finalize();
}
$this->initTargetDirectory(
$this->target . dirname($file->getId()) . '/'
);
$fileDom = $fileReport->asDom();
$fileDom->formatOutput = true;
$fileDom->preserveWhiteSpace = false;
$fileDom->save($this->target . $file->getId() . '.xml');
}
private function processUnit($unit, Report $report)
{
if (isset($unit['className'])) {
$unitObject = $report->getClassObject($unit['className']);
} else {
$unitObject = $report->getTraitObject($unit['traitName']);
}
$unitObject->setLines(
$unit['startLine'],
$unit['executableLines'],
$unit['executedLines']
);
$unitObject->setCrap($unit['crap']);
$unitObject->setPackage(
$unit['package']['fullPackage'],
$unit['package']['package'],
$unit['package']['subpackage'],
$unit['package']['category']
);
$unitObject->setNamespace($unit['package']['namespace']);
foreach ($unit['methods'] as $method) {
$methodObject = $unitObject->addMethod($method['methodName']);
$methodObject->setSignature($method['signature']);
$methodObject->setLines($method['startLine'], $method['endLine']);
$methodObject->setCrap($method['crap']);
$methodObject->setTotals(
$method['executableLines'],
$method['executedLines'],
$method['coverage']
);
}
}
private function processFunction($function, Report $report)
{
$functionObject = $report->getFunctionObject($function['functionName']);
$functionObject->setSignature($function['signature']);
$functionObject->setLines($function['startLine']);
$functionObject->setCrap($function['crap']);
$functionObject->setTotals($function['executableLines'], $function['executedLines'], $function['coverage']);
}
private function processTests(array $tests)
{
$testsObject = $this->project->getTests();
foreach ($tests as $test => $result) {
if ($test == 'UNCOVERED_FILES_FROM_WHITELIST') {
continue;
}
$testsObject->addTest($test, $result);
}
}
private function setTotals(AbstractNode $node, Totals $totals)
{
$loc = $node->getLinesOfCode();
$totals->setNumLines(
$loc['loc'],
$loc['cloc'],
$loc['ncloc'],
$node->getNumExecutableLines(),
$node->getNumExecutedLines()
);
$totals->setNumClasses(
$node->getNumClasses(),
$node->getNumTestedClasses()
);
$totals->setNumTraits(
$node->getNumTraits(),
$node->getNumTestedTraits()
);
$totals->setNumMethods(
$node->getNumMethods(),
$node->getNumTestedMethods()
);
$totals->setNumFunctions(
$node->getNumFunctions(),
$node->getNumTestedFunctions()
);
}
}

View File

@ -0,0 +1,72 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
class File
{
/**
* @var \DOMDocument
*/
protected $dom;
/**
* @var \DOMElement
*/
protected $contextNode;
public function __construct(\DOMElement $context)
{
$this->dom = $context->ownerDocument;
$this->contextNode = $context;
}
public function getTotals()
{
$totalsContainer = $this->contextNode->firstChild;
if (!$totalsContainer) {
$totalsContainer = $this->contextNode->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'totals'
)
);
}
return new Totals($totalsContainer);
}
public function getLineCoverage($line)
{
$coverage = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'coverage'
)->item(0);
if (!$coverage) {
$coverage = $this->contextNode->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'coverage'
)
);
}
$lineNode = $coverage->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'line'
)
);
return new Coverage($lineNode, $line);
}
}

View File

@ -0,0 +1,57 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
class Method
{
/**
* @var \DOMElement
*/
private $contextNode;
public function __construct(\DOMElement $context, $name)
{
$this->contextNode = $context;
$this->setName($name);
}
private function setName($name)
{
$this->contextNode->setAttribute('name', $name);
}
public function setSignature($signature)
{
$this->contextNode->setAttribute('signature', $signature);
}
public function setLines($start, $end = null)
{
$this->contextNode->setAttribute('start', $start);
if ($end !== null) {
$this->contextNode->setAttribute('end', $end);
}
}
public function setTotals($executable, $executed, $coverage)
{
$this->contextNode->setAttribute('executable', $executable);
$this->contextNode->setAttribute('executed', $executed);
$this->contextNode->setAttribute('coverage', $coverage);
}
public function setCrap($crap)
{
$this->contextNode->setAttribute('crap', $crap);
}
}

View File

@ -0,0 +1,88 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
class Node
{
/**
* @var \DOMDocument
*/
private $dom;
/**
* @var \DOMElement
*/
private $contextNode;
public function __construct(\DOMElement $context)
{
$this->setContextNode($context);
}
protected function setContextNode(\DOMElement $context)
{
$this->dom = $context->ownerDocument;
$this->contextNode = $context;
}
public function getDom()
{
return $this->dom;
}
protected function getContextNode()
{
return $this->contextNode;
}
public function getTotals()
{
$totalsContainer = $this->getContextNode()->firstChild;
if (!$totalsContainer) {
$totalsContainer = $this->getContextNode()->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'totals'
)
);
}
return new Totals($totalsContainer);
}
public function addDirectory($name)
{
$dirNode = $this->getDom()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'directory'
);
$dirNode->setAttribute('name', $name);
$this->getContextNode()->appendChild($dirNode);
return new Directory($dirNode);
}
public function addFile($name, $href)
{
$fileNode = $this->getDom()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'file'
);
$fileNode->setAttribute('name', $name);
$fileNode->setAttribute('href', $href);
$this->getContextNode()->appendChild($fileNode);
return new File($fileNode);
}
}

View File

@ -0,0 +1,62 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
class Project extends Node
{
public function __construct($name)
{
$this->init();
$this->setProjectName($name);
}
private function init()
{
$dom = new \DOMDocument;
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="http://schema.phpunit.de/coverage/1.0"><project/></phpunit>');
$this->setContextNode(
$dom->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'project'
)->item(0)
);
}
private function setProjectName($name)
{
$this->getContextNode()->setAttribute('name', $name);
}
public function getTests()
{
$testsNode = $this->getContextNode()->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'tests'
)->item(0);
if (!$testsNode) {
$testsNode = $this->getContextNode()->appendChild(
$this->getDom()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'tests'
)
);
}
return new Tests($testsNode);
}
public function asDom()
{
return $this->getDom();
}
}

View File

@ -0,0 +1,71 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
class Report extends File
{
public function __construct($name)
{
$this->dom = new \DOMDocument;
$this->dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="http://schema.phpunit.de/coverage/1.0"><file /></phpunit>');
$this->contextNode = $this->dom->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'file'
)->item(0);
$this->setName($name);
}
private function setName($name)
{
$this->contextNode->setAttribute('name', $name);
}
public function asDom()
{
return $this->dom;
}
public function getFunctionObject($name)
{
$node = $this->contextNode->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'function'
)
);
return new Method($node, $name);
}
public function getClassObject($name)
{
return $this->getUnitObject('class', $name);
}
public function getTraitObject($name)
{
return $this->getUnitObject('trait', $name);
}
private function getUnitObject($tagName, $name)
{
$node = $this->contextNode->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
$tagName
)
);
return new Unit($node, $name);
}
}

View File

@ -0,0 +1,46 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
class Tests
{
private $contextNode;
private $codeMap = [
0 => 'PASSED', // PHPUnit_Runner_BaseTestRunner::STATUS_PASSED
1 => 'SKIPPED', // PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED
2 => 'INCOMPLETE', // PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE
3 => 'FAILURE', // PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE
4 => 'ERROR', // PHPUnit_Runner_BaseTestRunner::STATUS_ERROR
5 => 'RISKY', // PHPUnit_Runner_BaseTestRunner::STATUS_RISKY
6 => 'WARNING' // PHPUnit_Runner_BaseTestRunner::STATUS_WARNING
];
public function __construct(\DOMElement $context)
{
$this->contextNode = $context;
}
public function addTest($test, array $result)
{
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'test'
)
);
$node->setAttribute('name', $test);
$node->setAttribute('size', $result['size']);
$node->setAttribute('result', (int) $result['status']);
$node->setAttribute('status', $this->codeMap[(int) $result['status']]);
}
}

View File

@ -0,0 +1,141 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
use SebastianBergmann\CodeCoverage\Util;
class Totals
{
/**
* @var \DOMNode
*/
private $container;
/**
* @var \DOMElement
*/
private $linesNode;
/**
* @var \DOMElement
*/
private $methodsNode;
/**
* @var \DOMElement
*/
private $functionsNode;
/**
* @var \DOMElement
*/
private $classesNode;
/**
* @var \DOMElement
*/
private $traitsNode;
public function __construct(\DOMElement $container)
{
$this->container = $container;
$dom = $container->ownerDocument;
$this->linesNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'lines'
);
$this->methodsNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'methods'
);
$this->functionsNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'functions'
);
$this->classesNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'classes'
);
$this->traitsNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'traits'
);
$container->appendChild($this->linesNode);
$container->appendChild($this->methodsNode);
$container->appendChild($this->functionsNode);
$container->appendChild($this->classesNode);
$container->appendChild($this->traitsNode);
}
public function getContainer()
{
return $this->container;
}
public function setNumLines($loc, $cloc, $ncloc, $executable, $executed)
{
$this->linesNode->setAttribute('total', $loc);
$this->linesNode->setAttribute('comments', $cloc);
$this->linesNode->setAttribute('code', $ncloc);
$this->linesNode->setAttribute('executable', $executable);
$this->linesNode->setAttribute('executed', $executed);
$this->linesNode->setAttribute(
'percent',
Util::percent($executed, $executable, true)
);
}
public function setNumClasses($count, $tested)
{
$this->classesNode->setAttribute('count', $count);
$this->classesNode->setAttribute('tested', $tested);
$this->classesNode->setAttribute(
'percent',
Util::percent($tested, $count, true)
);
}
public function setNumTraits($count, $tested)
{
$this->traitsNode->setAttribute('count', $count);
$this->traitsNode->setAttribute('tested', $tested);
$this->traitsNode->setAttribute(
'percent',
Util::percent($tested, $count, true)
);
}
public function setNumMethods($count, $tested)
{
$this->methodsNode->setAttribute('count', $count);
$this->methodsNode->setAttribute('tested', $tested);
$this->methodsNode->setAttribute(
'percent',
Util::percent($tested, $count, true)
);
}
public function setNumFunctions($count, $tested)
{
$this->functionsNode->setAttribute('count', $count);
$this->functionsNode->setAttribute('tested', $tested);
$this->functionsNode->setAttribute(
'percent',
Util::percent($tested, $count, true)
);
}
}

View File

@ -0,0 +1,96 @@
<?php
/*
* This file is part of the php-code-coverage package.
*
* (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\Xml;
class Unit
{
/**
* @var \DOMElement
*/
private $contextNode;
public function __construct(\DOMElement $context, $name)
{
$this->contextNode = $context;
$this->setName($name);
}
private function setName($name)
{
$this->contextNode->setAttribute('name', $name);
}
public function setLines($start, $executable, $executed)
{
$this->contextNode->setAttribute('start', $start);
$this->contextNode->setAttribute('executable', $executable);
$this->contextNode->setAttribute('executed', $executed);
}
public function setCrap($crap)
{
$this->contextNode->setAttribute('crap', $crap);
}
public function setPackage($full, $package, $sub, $category)
{
$node = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'package'
)->item(0);
if (!$node) {
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'package'
)
);
}
$node->setAttribute('full', $full);
$node->setAttribute('name', $package);
$node->setAttribute('sub', $sub);
$node->setAttribute('category', $category);
}
public function setNamespace($namespace)
{
$node = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'namespace'
)->item(0);
if (!$node) {
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'namespace'
)
);
}
$node->setAttribute('name', $namespace);
}
public function addMethod($name)
{
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'method'
)
);
return new Method($node, $name);
}
}