Laravel 5.6 updates

Travis config update

Removed HHVM script as Laravel no longer support HHVM after releasing 5.3
This commit is contained in:
Manish Verma
2018-08-06 20:08:55 +05:30
parent 126fbb0255
commit 1ac0f42a58
2464 changed files with 65239 additions and 46734 deletions

View File

@@ -12,8 +12,8 @@ namespace SebastianBergmann\CodeCoverage;
use PHPUnit\Framework\TestCase;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Util\Test;
use SebastianBergmann\CodeCoverage\Driver\Driver;
use SebastianBergmann\CodeCoverage\Driver\HHVM;
use SebastianBergmann\CodeCoverage\Driver\PHPDBG;
use SebastianBergmann\CodeCoverage\Driver\Xdebug;
use SebastianBergmann\CodeCoverage\Node\Builder;
@@ -24,7 +24,7 @@ use SebastianBergmann\Environment\Runtime;
/**
* Provides collection functionality for PHP code coverage information.
*/
class CodeCoverage
final class CodeCoverage
{
/**
* @var Driver
@@ -82,7 +82,7 @@ class CodeCoverage
private $ignoreDeprecatedCode = false;
/**
* @var mixed
* @var PhptTestCase|string|TestCase
*/
private $currentId;
@@ -135,11 +135,6 @@ class CodeCoverage
private $report;
/**
* Constructor.
*
* @param Driver $driver
* @param Filter $filter
*
* @throws RuntimeException
*/
public function __construct(Driver $driver = null, Filter $filter = null)
@@ -160,10 +155,8 @@ class CodeCoverage
/**
* Returns the code coverage information as a graph of node objects.
*
* @return Directory
*/
public function getReport()
public function getReport(): Directory
{
if ($this->report === null) {
$builder = new Builder;
@@ -177,7 +170,7 @@ class CodeCoverage
/**
* Clears collected code coverage data.
*/
public function clear()
public function clear(): void
{
$this->isInitialized = false;
$this->currentId = null;
@@ -188,10 +181,8 @@ class CodeCoverage
/**
* Returns the filter object used.
*
* @return Filter
*/
public function filter()
public function filter(): Filter
{
return $this->filter;
}
@@ -199,12 +190,8 @@ class CodeCoverage
/**
* Returns the collected code coverage data.
* Set $raw = true to bypass all filters.
*
* @param bool $raw
*
* @return array
*/
public function getData($raw = false)
public function getData(bool $raw = false): array
{
if (!$raw && $this->addUncoveredFilesFromWhitelist) {
$this->addUncoveredFilesFromWhitelist();
@@ -215,10 +202,8 @@ class CodeCoverage
/**
* Sets the coverage data.
*
* @param array $data
*/
public function setData(array $data)
public function setData(array $data): void
{
$this->data = $data;
$this->report = null;
@@ -226,20 +211,16 @@ class CodeCoverage
/**
* Returns the test data.
*
* @return array
*/
public function getTests()
public function getTests(): array
{
return $this->tests;
}
/**
* Sets the test data.
*
* @param array $tests
*/
public function setTests(array $tests)
public function setTests(array $tests): void
{
$this->tests = $tests;
}
@@ -247,20 +228,13 @@ class CodeCoverage
/**
* Start collection of code coverage information.
*
* @param mixed $id
* @param bool $clear
* @param PhptTestCase|string|TestCase $id
* @param bool $clear
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function start($id, $clear = false)
public function start($id, bool $clear = false): void
{
if (!\is_bool($clear)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
if ($clear) {
$this->clear();
}
@@ -277,25 +251,16 @@ class CodeCoverage
/**
* Stop collection of code coverage information.
*
* @param bool $append
* @param mixed $linesToBeCovered
* @param array $linesToBeUsed
* @param bool $ignoreForceCoversAnnotation
* @param array|false $linesToBeCovered
*
* @return array
*
* @throws \SebastianBergmann\CodeCoverage\RuntimeException
* @throws MissingCoversAnnotationException
* @throws CoveredCodeNotExecutedException
* @throws RuntimeException
* @throws InvalidArgumentException
* @throws \ReflectionException
*/
public function stop($append = true, $linesToBeCovered = [], array $linesToBeUsed = [], $ignoreForceCoversAnnotation = false)
public function stop(bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): array
{
if (!\is_bool($append)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
if (!\is_array($linesToBeCovered) && $linesToBeCovered !== false) {
throw InvalidArgumentException::create(
2,
@@ -314,12 +279,8 @@ class CodeCoverage
/**
* Appends code coverage data.
*
* @param array $data
* @param mixed $id
* @param bool $append
* @param mixed $linesToBeCovered
* @param array $linesToBeUsed
* @param bool $ignoreForceCoversAnnotation
* @param PhptTestCase|string|TestCase $id
* @param array|false $linesToBeCovered
*
* @throws \SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException
* @throws \SebastianBergmann\CodeCoverage\MissingCoversAnnotationException
@@ -328,7 +289,7 @@ class CodeCoverage
* @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
* @throws RuntimeException
*/
public function append(array $data, $id = null, $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], $ignoreForceCoversAnnotation = false)
public function append(array $data, $id = null, bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): void
{
if ($id === null) {
$id = $this->currentId;
@@ -338,7 +299,7 @@ class CodeCoverage
throw new RuntimeException;
}
$this->applyListsFilter($data);
$this->applyWhitelistFilter($data);
$this->applyIgnoredLinesFilter($data);
$this->initializeFilesThatAreSeenTheFirstTime($data);
@@ -360,16 +321,16 @@ class CodeCoverage
}
$size = 'unknown';
$status = null;
$status = -1;
if ($id instanceof TestCase) {
$_size = $id->getSize();
if ($_size === \PHPUnit\Util\Test::SMALL) {
if ($_size === Test::SMALL) {
$size = 'small';
} elseif ($_size === \PHPUnit\Util\Test::MEDIUM) {
} elseif ($_size === Test::MEDIUM) {
$size = 'medium';
} elseif ($_size === \PHPUnit\Util\Test::LARGE) {
} elseif ($_size === Test::LARGE) {
$size = 'large';
}
@@ -404,7 +365,7 @@ class CodeCoverage
*
* @param CodeCoverage $that
*/
public function merge(self $that)
public function merge(self $that): void
{
$this->filter->setWhitelistedFiles(
\array_merge($this->filter->getWhitelistedFiles(), $that->filter()->getWhitelistedFiles())
@@ -419,15 +380,24 @@ class CodeCoverage
continue;
}
foreach ($lines as $line => $data) {
if ($data !== null) {
if (!isset($this->data[$file][$line])) {
$this->data[$file][$line] = $data;
} else {
$this->data[$file][$line] = \array_unique(
\array_merge($this->data[$file][$line], $data)
);
}
// we should compare the lines if any of two contains data
$compareLineNumbers = \array_unique(
\array_merge(
\array_keys($this->data[$file]),
\array_keys($that->data[$file])
)
);
foreach ($compareLineNumbers as $line) {
$thatPriority = $this->getLinePriority($that->data[$file], $line);
$thisPriority = $this->getLinePriority($this->data[$file], $line);
if ($thatPriority > $thisPriority) {
$this->data[$file][$line] = $that->data[$file][$line];
} elseif ($thatPriority === $thisPriority && \is_array($this->data[$file][$line])) {
$this->data[$file][$line] = \array_unique(
\array_merge($this->data[$file][$line], $that->data[$file][$line])
);
}
}
}
@@ -436,200 +406,104 @@ class CodeCoverage
$this->report = null;
}
/**
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setCacheTokens($flag)
public function setCacheTokens(bool $flag): void
{
if (!\is_bool($flag)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
$this->cacheTokens = $flag;
}
/**
* @return bool
*/
public function getCacheTokens()
public function getCacheTokens(): bool
{
return $this->cacheTokens;
}
/**
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setCheckForUnintentionallyCoveredCode($flag)
public function setCheckForUnintentionallyCoveredCode(bool $flag): void
{
if (!\is_bool($flag)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
$this->checkForUnintentionallyCoveredCode = $flag;
}
/**
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setForceCoversAnnotation($flag)
public function setForceCoversAnnotation(bool $flag): void
{
if (!\is_bool($flag)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
$this->forceCoversAnnotation = $flag;
}
/**
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setCheckForMissingCoversAnnotation($flag)
public function setCheckForMissingCoversAnnotation(bool $flag): void
{
if (!\is_bool($flag)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
$this->checkForMissingCoversAnnotation = $flag;
}
/**
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setCheckForUnexecutedCoveredCode($flag)
public function setCheckForUnexecutedCoveredCode(bool $flag): void
{
if (!\is_bool($flag)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
$this->checkForUnexecutedCoveredCode = $flag;
}
/**
* @deprecated
*
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setMapTestClassNameToCoveredClassName($flag)
public function setAddUncoveredFilesFromWhitelist(bool $flag): void
{
}
/**
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setAddUncoveredFilesFromWhitelist($flag)
{
if (!\is_bool($flag)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
$this->addUncoveredFilesFromWhitelist = $flag;
}
/**
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setProcessUncoveredFilesFromWhitelist($flag)
public function setProcessUncoveredFilesFromWhitelist(bool $flag): void
{
if (!\is_bool($flag)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
$this->processUncoveredFilesFromWhitelist = $flag;
}
/**
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setDisableIgnoredLines($flag)
public function setDisableIgnoredLines(bool $flag): void
{
if (!\is_bool($flag)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
$this->disableIgnoredLines = $flag;
}
/**
* @param bool $flag
*
* @throws InvalidArgumentException
*/
public function setIgnoreDeprecatedCode($flag)
public function setIgnoreDeprecatedCode(bool $flag): void
{
if (!\is_bool($flag)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
$this->ignoreDeprecatedCode = $flag;
}
/**
* @param array $whitelist
*/
public function setUnintentionallyCoveredSubclassesWhitelist(array $whitelist)
public function setUnintentionallyCoveredSubclassesWhitelist(array $whitelist): void
{
$this->unintentionallyCoveredSubclassesWhitelist = $whitelist;
}
/**
* Applies the @covers annotation filtering.
* Determine the priority for a line
*
* 1 = the line is not set
* 2 = the line has not been tested
* 3 = the line is dead code
* 4 = the line has been tested
*
* During a merge, a higher number is better.
*
* @param array $data
* @param mixed $linesToBeCovered
* @param array $linesToBeUsed
* @param bool $ignoreForceCoversAnnotation
* @param int $line
*
* @return int
*/
private function getLinePriority($data, $line)
{
if (!\array_key_exists($line, $data)) {
return 1;
}
if (\is_array($data[$line]) && \count($data[$line]) === 0) {
return 2;
}
if ($data[$line] === null) {
return 3;
}
return 4;
}
/**
* Applies the @covers annotation filtering.
*
* @param array|false $linesToBeCovered
*
* @throws \SebastianBergmann\CodeCoverage\CoveredCodeNotExecutedException
* @throws \ReflectionException
* @throws MissingCoversAnnotationException
* @throws UnintentionallyCoveredCodeException
*/
private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, array $linesToBeUsed, $ignoreForceCoversAnnotation)
private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, array $linesToBeUsed, bool $ignoreForceCoversAnnotation): void
{
if ($linesToBeCovered === false ||
($this->forceCoversAnnotation && empty($linesToBeCovered) && !$ignoreForceCoversAnnotation)) {
@@ -664,12 +538,7 @@ class CodeCoverage
}
}
/**
* Applies the whitelist filtering.
*
* @param array $data
*/
private function applyListsFilter(array &$data)
private function applyWhitelistFilter(array &$data): void
{
foreach (\array_keys($data) as $filename) {
if ($this->filter->isFiltered($filename)) {
@@ -679,13 +548,9 @@ class CodeCoverage
}
/**
* Applies the "ignored lines" filtering.
*
* @param array $data
*
* @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
*/
private function applyIgnoredLinesFilter(array &$data)
private function applyIgnoredLinesFilter(array &$data): void
{
foreach (\array_keys($data) as $filename) {
if (!$this->filter->isFile($filename)) {
@@ -698,10 +563,7 @@ class CodeCoverage
}
}
/**
* @param array $data
*/
private function initializeFilesThatAreSeenTheFirstTime(array $data)
private function initializeFilesThatAreSeenTheFirstTime(array $data): void
{
foreach ($data as $file => $lines) {
if (!isset($this->data[$file]) && $this->filter->isFile($file)) {
@@ -715,9 +577,14 @@ class CodeCoverage
}
/**
* Processes whitelisted files that are not covered.
* @throws CoveredCodeNotExecutedException
* @throws InvalidArgumentException
* @throws MissingCoversAnnotationException
* @throws RuntimeException
* @throws UnintentionallyCoveredCodeException
* @throws \ReflectionException
*/
private function addUncoveredFilesFromWhitelist()
private function addUncoveredFilesFromWhitelist(): void
{
$data = [];
$uncoveredFiles = \array_diff(
@@ -742,42 +609,26 @@ class CodeCoverage
$this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
}
/**
* Returns the lines of a source file that should be ignored.
*
* @param string $filename
*
* @return array
*
* @throws InvalidArgumentException
*/
private function getLinesToBeIgnored($filename)
private function getLinesToBeIgnored(string $fileName): array
{
if (!\is_string($filename)) {
throw InvalidArgumentException::create(
1,
'string'
);
if (isset($this->ignoredLines[$fileName])) {
return $this->ignoredLines[$fileName];
}
if (isset($this->ignoredLines[$filename])) {
return $this->ignoredLines[$filename];
}
$this->ignoredLines[$fileName] = [];
$this->ignoredLines[$filename] = [];
$lines = \file($filename);
$lines = \file($fileName);
foreach ($lines as $index => $line) {
if (!\trim($line)) {
$this->ignoredLines[$filename][] = $index + 1;
$this->ignoredLines[$fileName][] = $index + 1;
}
}
if ($this->cacheTokens) {
$tokens = \PHP_Token_Stream_CachingFactory::get($filename);
$tokens = \PHP_Token_Stream_CachingFactory::get($fileName);
} else {
$tokens = new \PHP_Token_Stream($filename);
$tokens = new \PHP_Token_Stream($fileName);
}
foreach ($tokens->getInterfaces() as $interface) {
@@ -785,7 +636,7 @@ class CodeCoverage
$interfaceEndLine = $interface['endLine'];
foreach (\range($interfaceStartLine, $interfaceEndLine) as $line) {
$this->ignoredLines[$filename][] = $line;
$this->ignoredLines[$fileName][] = $line;
}
}
@@ -795,7 +646,7 @@ class CodeCoverage
if (empty($classOrTrait['methods'])) {
foreach (\range($classOrTraitStartLine, $classOrTraitEndLine) as $line) {
$this->ignoredLines[$filename][] = $line;
$this->ignoredLines[$fileName][] = $line;
}
continue;
@@ -815,19 +666,19 @@ class CodeCoverage
}
foreach (\range($classOrTraitStartLine, $firstMethodStartLine) as $line) {
$this->ignoredLines[$filename][] = $line;
$this->ignoredLines[$fileName][] = $line;
}
foreach (\range($lastMethodEndLine + 1, $classOrTraitEndLine) as $line) {
$this->ignoredLines[$filename][] = $line;
$this->ignoredLines[$fileName][] = $line;
}
}
if ($this->disableIgnoredLines) {
$this->ignoredLines[$filename] = array_unique($this->ignoredLines[$filename]);
\sort($this->ignoredLines[$filename]);
$this->ignoredLines[$fileName] = \array_unique($this->ignoredLines[$fileName]);
\sort($this->ignoredLines[$fileName]);
return $this->ignoredLines[$filename];
return $this->ignoredLines[$fileName];
}
$ignore = false;
@@ -863,13 +714,13 @@ class CodeCoverage
}
for ($i = $start; $i < $end; $i++) {
$this->ignoredLines[$filename][] = $i;
$this->ignoredLines[$fileName][] = $i;
}
// A DOC_COMMENT token or a COMMENT token starting with "/*"
// does not contain the final \n character in its text
if (isset($lines[$i - 1]) && 0 === \strpos($_token, '/*') && '*/' === \substr(\trim($lines[$i - 1]), -2)) {
$this->ignoredLines[$filename][] = $i;
$this->ignoredLines[$fileName][] = $i;
}
}
@@ -883,38 +734,34 @@ class CodeCoverage
$docblock = $token->getDocblock();
$this->ignoredLines[$filename][] = $token->getLine();
$this->ignoredLines[$fileName][] = $token->getLine();
if (\strpos($docblock, '@codeCoverageIgnore') || ($this->ignoreDeprecatedCode && \strpos($docblock, '@deprecated'))) {
$endLine = $token->getEndLine();
for ($i = $token->getLine(); $i <= $endLine; $i++) {
$this->ignoredLines[$filename][] = $i;
$this->ignoredLines[$fileName][] = $i;
}
}
break;
case \PHP_Token_ENUM::class:
$this->ignoredLines[$filename][] = $token->getLine();
break;
/* @noinspection PhpMissingBreakStatementInspection */
case \PHP_Token_NAMESPACE::class:
$this->ignoredLines[$filename][] = $token->getEndLine();
$this->ignoredLines[$fileName][] = $token->getEndLine();
// Intentional fallthrough
case \PHP_Token_DECLARE::class:
case \PHP_Token_OPEN_TAG::class:
case \PHP_Token_CLOSE_TAG::class:
case \PHP_Token_USE::class:
$this->ignoredLines[$filename][] = $token->getLine();
$this->ignoredLines[$fileName][] = $token->getLine();
break;
}
if ($ignore) {
$this->ignoredLines[$filename][] = $token->getLine();
$this->ignoredLines[$fileName][] = $token->getLine();
if ($stop) {
$ignore = false;
@@ -923,27 +770,23 @@ class CodeCoverage
}
}
$this->ignoredLines[$filename][] = \count($lines) + 1;
$this->ignoredLines[$fileName][] = \count($lines) + 1;
$this->ignoredLines[$filename] = \array_unique(
$this->ignoredLines[$filename]
$this->ignoredLines[$fileName] = \array_unique(
$this->ignoredLines[$fileName]
);
$this->ignoredLines[$filename] = array_unique($this->ignoredLines[$filename]);
\sort($this->ignoredLines[$filename]);
$this->ignoredLines[$fileName] = \array_unique($this->ignoredLines[$fileName]);
\sort($this->ignoredLines[$fileName]);
return $this->ignoredLines[$filename];
return $this->ignoredLines[$fileName];
}
/**
* @param array $data
* @param array $linesToBeCovered
* @param array $linesToBeUsed
*
* @throws \ReflectionException
* @throws UnintentionallyCoveredCodeException
*/
private function performUnintentionallyCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed)
private function performUnintentionallyCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed): void
{
$allowedLines = $this->getAllowedLines(
$linesToBeCovered,
@@ -970,13 +813,9 @@ class CodeCoverage
}
/**
* @param array $data
* @param array $linesToBeCovered
* @param array $linesToBeUsed
*
* @throws CoveredCodeNotExecutedException
*/
private function performUnexecutedCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed)
private function performUnexecutedCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed): void
{
$executedCodeUnits = $this->coverageToCodeUnits($data);
$message = '';
@@ -1004,13 +843,7 @@ class CodeCoverage
}
}
/**
* @param array $linesToBeCovered
* @param array $linesToBeUsed
*
* @return array
*/
private function getAllowedLines(array $linesToBeCovered, array $linesToBeUsed)
private function getAllowedLines(array $linesToBeCovered, array $linesToBeUsed): array
{
$allowedLines = [];
@@ -1046,11 +879,9 @@ class CodeCoverage
}
/**
* @return Driver
*
* @throws RuntimeException
*/
private function selectDriver()
private function selectDriver(): Driver
{
$runtime = new Runtime;
@@ -1058,25 +889,18 @@ class CodeCoverage
throw new RuntimeException('No code coverage driver available');
}
if ($runtime->isHHVM()) {
return new HHVM;
}
if ($runtime->isPHPDBG()) {
return new PHPDBG;
}
return new Xdebug;
if ($runtime->hasXdebug()) {
return new Xdebug;
}
throw new RuntimeException('No code coverage driver available');
}
/**
* @param array $unintentionallyCoveredUnits
*
* @return array
*
* @throws \ReflectionException
*/
private function processUnintentionallyCoveredUnits(array $unintentionallyCoveredUnits)
private function processUnintentionallyCoveredUnits(array $unintentionallyCoveredUnits): array
{
$unintentionallyCoveredUnits = \array_unique($unintentionallyCoveredUnits);
\sort($unintentionallyCoveredUnits);
@@ -1103,23 +927,25 @@ class CodeCoverage
}
/**
* If we are processing uncovered files from whitelist,
* we can initialize the data before we start to speed up the tests
*
* @throws \SebastianBergmann\CodeCoverage\RuntimeException
* @throws CoveredCodeNotExecutedException
* @throws InvalidArgumentException
* @throws MissingCoversAnnotationException
* @throws RuntimeException
* @throws UnintentionallyCoveredCodeException
* @throws \ReflectionException
*/
protected function initializeData()
private function initializeData(): void
{
$this->isInitialized = true;
if ($this->processUncoveredFilesFromWhitelist) {
$this->shouldCheckForDeadAndUnused = false;
$this->driver->start(true);
$this->driver->start();
foreach ($this->filter->getWhitelist() as $file) {
if ($this->filter->isFile($file)) {
include_once($file);
include_once $file;
}
}
@@ -1144,12 +970,7 @@ class CodeCoverage
}
}
/**
* @param array $data
*
* @return array
*/
private function coverageToCodeUnits(array $data)
private function coverageToCodeUnits(array $data): array
{
$codeUnits = [];
@@ -1164,12 +985,7 @@ class CodeCoverage
return \array_unique($codeUnits);
}
/**
* @param array $data
*
* @return array
*/
private function linesToCodeUnits(array $data)
private function linesToCodeUnits(array $data): array
{
$codeUnits = [];

View File

@@ -20,33 +20,29 @@ interface Driver
*
* @see http://xdebug.org/docs/code_coverage
*/
const LINE_EXECUTED = 1;
public const LINE_EXECUTED = 1;
/**
* @var int
*
* @see http://xdebug.org/docs/code_coverage
*/
const LINE_NOT_EXECUTED = -1;
public const LINE_NOT_EXECUTED = -1;
/**
* @var int
*
* @see http://xdebug.org/docs/code_coverage
*/
const LINE_NOT_EXECUTABLE = -2;
public const LINE_NOT_EXECUTABLE = -2;
/**
* Start collection of code coverage information.
*
* @param bool $determineUnusedAndDead
*/
public function start($determineUnusedAndDead = true);
public function start(bool $determineUnusedAndDead = true): void;
/**
* Stop collection of code coverage information.
*
* @return array
*/
public function stop();
public function stop(): array;
}

View File

@@ -1,29 +0,0 @@
<?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\Driver;
/**
* Driver for HHVM's code coverage functionality.
*
* @codeCoverageIgnore
*/
class HHVM extends Xdebug
{
/**
* Start collection of code coverage information.
*
* @param bool $determineUnusedAndDead
*/
public function start($determineUnusedAndDead = true)
{
\xdebug_start_code_coverage();
}
}

View File

@@ -17,10 +17,10 @@ use SebastianBergmann\CodeCoverage\RuntimeException;
*
* @codeCoverageIgnore
*/
class PHPDBG implements Driver
final class PHPDBG implements Driver
{
/**
* Constructor.
* @throws RuntimeException
*/
public function __construct()
{
@@ -39,39 +39,30 @@ class PHPDBG implements Driver
/**
* Start collection of code coverage information.
*
* @param bool $determineUnusedAndDead
*/
public function start($determineUnusedAndDead = true)
public function start(bool $determineUnusedAndDead = true): void
{
phpdbg_start_oplog();
\phpdbg_start_oplog();
}
/**
* Stop collection of code coverage information.
*
* @return array
*/
public function stop()
public function stop(): array
{
static $fetchedLines = [];
$dbgData = phpdbg_end_oplog();
$dbgData = \phpdbg_end_oplog();
if ($fetchedLines == []) {
$sourceLines = phpdbg_get_executable();
$sourceLines = \phpdbg_get_executable();
} else {
$newFiles = \array_diff(
\get_included_files(),
\array_keys($fetchedLines)
);
$newFiles = \array_diff(\get_included_files(), \array_keys($fetchedLines));
$sourceLines = [];
if ($newFiles) {
$sourceLines = phpdbg_get_executable(
['files' => $newFiles]
);
} else {
$sourceLines = [];
$sourceLines = phpdbg_get_executable(['files' => $newFiles]);
}
}
@@ -88,13 +79,8 @@ class PHPDBG implements Driver
/**
* Convert phpdbg based data into the format CodeCoverage expects
*
* @param array $sourceLines
* @param array $dbgData
*
* @return array
*/
private function detectExecutedLines(array $sourceLines, array $dbgData)
private function detectExecutedLines(array $sourceLines, array $dbgData): array
{
foreach ($dbgData as $file => $coveredLines) {
foreach ($coveredLines as $lineNo => $numExecuted) {

View File

@@ -17,17 +17,15 @@ use SebastianBergmann\CodeCoverage\RuntimeException;
*
* @codeCoverageIgnore
*/
class Xdebug implements Driver
final class Xdebug implements Driver
{
/**
* Cache the number of lines for each file
*
* @var array
*/
private $cacheNumLines = [];
/**
* Constructor.
* @throws RuntimeException
*/
public function __construct()
{
@@ -35,20 +33,15 @@ class Xdebug implements Driver
throw new RuntimeException('This driver requires Xdebug');
}
if (\version_compare(\phpversion('xdebug'), '2.2.1', '>=') &&
!\ini_get('xdebug.coverage_enable')) {
throw new RuntimeException(
'xdebug.coverage_enable=On has to be set in php.ini'
);
if (!\ini_get('xdebug.coverage_enable')) {
throw new RuntimeException('xdebug.coverage_enable=On has to be set in php.ini');
}
}
/**
* Start collection of code coverage information.
*
* @param bool $determineUnusedAndDead
*/
public function start($determineUnusedAndDead = true)
public function start(bool $determineUnusedAndDead = true): void
{
if ($determineUnusedAndDead) {
\xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
@@ -59,23 +52,17 @@ class Xdebug implements Driver
/**
* Stop collection of code coverage information.
*
* @return array
*/
public function stop()
public function stop(): array
{
$data = \xdebug_get_code_coverage();
\xdebug_stop_code_coverage();
return $this->cleanup($data);
}
/**
* @param array $data
*
* @return array
*/
private function cleanup(array $data)
private function cleanup(array $data): array
{
foreach (\array_keys($data) as $file) {
unset($data[$file][0]);
@@ -94,24 +81,19 @@ class Xdebug implements Driver
return $data;
}
/**
* @param string $file
*
* @return int
*/
private function getNumberOfLinesInFile($file)
private function getNumberOfLinesInFile(string $fileName): int
{
if (!isset($this->cacheNumLines[$file])) {
$buffer = \file_get_contents($file);
if (!isset($this->cacheNumLines[$fileName])) {
$buffer = \file_get_contents($fileName);
$lines = \substr_count($buffer, "\n");
if (\substr($buffer, -1) !== "\n") {
$lines++;
}
$this->cacheNumLines[$file] = $lines;
$this->cacheNumLines[$fileName] = $lines;
}
return $this->cacheNumLines[$file];
return $this->cacheNumLines[$fileName];
}
}

View File

@@ -13,6 +13,6 @@ namespace SebastianBergmann\CodeCoverage;
/**
* Exception that is raised when covered code is not executed.
*/
class CoveredCodeNotExecutedException extends RuntimeException
final class CoveredCodeNotExecutedException extends RuntimeException
{
}

View File

@@ -10,7 +10,7 @@
namespace SebastianBergmann\CodeCoverage;
class InvalidArgumentException extends \InvalidArgumentException implements Exception
final class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
/**
* @param int $argument
@@ -19,7 +19,7 @@ class InvalidArgumentException extends \InvalidArgumentException implements Exce
*
* @return InvalidArgumentException
*/
public static function create($argument, $type, $value = null)
public static function create($argument, $type, $value = null): self
{
$stack = \debug_backtrace(0);

View File

@@ -13,6 +13,6 @@ namespace SebastianBergmann\CodeCoverage;
/**
* Exception that is raised when @covers must be used but is not.
*/
class MissingCoversAnnotationException extends RuntimeException
final class MissingCoversAnnotationException extends RuntimeException
{
}

View File

@@ -13,7 +13,7 @@ namespace SebastianBergmann\CodeCoverage;
/**
* Exception that is raised when code is unintentionally covered.
*/
class UnintentionallyCoveredCodeException extends RuntimeException
final class UnintentionallyCoveredCodeException extends RuntimeException
{
/**
* @var array
@@ -33,7 +33,7 @@ class UnintentionallyCoveredCodeException extends RuntimeException
/**
* @return array
*/
public function getUnintentionallyCoveredUnits()
public function getUnintentionallyCoveredUnits(): array
{
return $this->unintentionallyCoveredUnits;
}
@@ -41,7 +41,7 @@ class UnintentionallyCoveredCodeException extends RuntimeException
/**
* @return string
*/
private function toString()
private function toString(): string
{
$message = '';

View File

@@ -10,10 +10,12 @@
namespace SebastianBergmann\CodeCoverage;
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
/**
* Filter for whitelisting of code coverage information.
*/
class Filter
final class Filter
{
/**
* Source files that are whitelisted.
@@ -24,14 +26,10 @@ class Filter
/**
* Adds a directory to the whitelist (recursively).
*
* @param string $directory
* @param string $suffix
* @param string $prefix
*/
public function addDirectoryToWhitelist($directory, $suffix = '.php', $prefix = '')
public function addDirectoryToWhitelist(string $directory, string $suffix = '.php', string $prefix = ''): void
{
$facade = new \File_Iterator_Facade;
$facade = new FileIteratorFacade;
$files = $facade->getFilesAsArray($directory, $suffix, $prefix);
foreach ($files as $file) {
@@ -41,10 +39,8 @@ class Filter
/**
* Adds a file to the whitelist.
*
* @param string $filename
*/
public function addFileToWhitelist($filename)
public function addFileToWhitelist(string $filename): void
{
$this->whitelistedFiles[\realpath($filename)] = true;
}
@@ -52,9 +48,9 @@ class Filter
/**
* Adds files to the whitelist.
*
* @param array $files
* @param string[] $files
*/
public function addFilesToWhitelist(array $files)
public function addFilesToWhitelist(array $files): void
{
foreach ($files as $file) {
$this->addFileToWhitelist($file);
@@ -63,14 +59,10 @@ class Filter
/**
* Removes a directory from the whitelist (recursively).
*
* @param string $directory
* @param string $suffix
* @param string $prefix
*/
public function removeDirectoryFromWhitelist($directory, $suffix = '.php', $prefix = '')
public function removeDirectoryFromWhitelist(string $directory, string $suffix = '.php', string $prefix = ''): void
{
$facade = new \File_Iterator_Facade;
$facade = new FileIteratorFacade;
$files = $facade->getFilesAsArray($directory, $suffix, $prefix);
foreach ($files as $file) {
@@ -80,10 +72,8 @@ class Filter
/**
* Removes a file from the whitelist.
*
* @param string $filename
*/
public function removeFileFromWhitelist($filename)
public function removeFileFromWhitelist(string $filename): void
{
$filename = \realpath($filename);
@@ -92,14 +82,10 @@ class Filter
/**
* Checks whether a filename is a real filename.
*
* @param string $filename
*
* @return bool
*/
public function isFile($filename)
public function isFile(string $filename): bool
{
if ($filename == '-' ||
if ($filename === '-' ||
\strpos($filename, 'vfs://') === 0 ||
\strpos($filename, 'xdebug://debug-eval') !== false ||
\strpos($filename, 'eval()\'d code') !== false ||
@@ -115,12 +101,8 @@ class Filter
/**
* Checks whether or not a file is filtered.
*
* @param string $filename
*
* @return bool
*/
public function isFiltered($filename)
public function isFiltered(string $filename): bool
{
if (!$this->isFile($filename)) {
return true;
@@ -134,19 +116,17 @@ class Filter
/**
* Returns the list of whitelisted files.
*
* @return array
* @return string[]
*/
public function getWhitelist()
public function getWhitelist(): array
{
return \array_keys($this->whitelistedFiles);
}
/**
* Returns whether this filter has a whitelist.
*
* @return bool
*/
public function hasWhitelist()
public function hasWhitelist(): bool
{
return !empty($this->whitelistedFiles);
}
@@ -154,19 +134,17 @@ class Filter
/**
* Returns the whitelisted files.
*
* @return array
* @return string[]
*/
public function getWhitelistedFiles()
public function getWhitelistedFiles(): array
{
return $this->whitelistedFiles;
}
/**
* Sets the whitelisted files.
*
* @param array $whitelistedFiles
*/
public function setWhitelistedFiles($whitelistedFiles)
public function setWhitelistedFiles(array $whitelistedFiles): void
{
$this->whitelistedFiles = $whitelistedFiles;
}

View File

@@ -42,13 +42,7 @@ abstract class AbstractNode implements \Countable
*/
private $id;
/**
* Constructor.
*
* @param string $name
* @param AbstractNode $parent
*/
public function __construct($name, self $parent = null)
public function __construct(string $name, self $parent = null)
{
if (\substr($name, -1) == '/') {
$name = \substr($name, 0, -1);
@@ -58,18 +52,12 @@ abstract class AbstractNode implements \Countable
$this->parent = $parent;
}
/**
* @return string
*/
public function getName()
public function getName(): string
{
return $this->name;
}
/**
* @return string
*/
public function getId()
public function getId(): string
{
if ($this->id === null) {
$parent = $this->getParent();
@@ -79,7 +67,7 @@ abstract class AbstractNode implements \Countable
} else {
$parentId = $parent->getId();
if ($parentId == 'index') {
if ($parentId === 'index') {
$this->id = \str_replace(':', '_', $this->name);
} else {
$this->id = $parentId . '/' . $this->name;
@@ -90,10 +78,7 @@ abstract class AbstractNode implements \Countable
return $this->id;
}
/**
* @return string
*/
public function getPath()
public function getPath(): string
{
if ($this->path === null) {
if ($this->parent === null || $this->parent->getPath() === null || $this->parent->getPath() === false) {
@@ -106,10 +91,7 @@ abstract class AbstractNode implements \Countable
return $this->path;
}
/**
* @return array
*/
public function getPathAsArray()
public function getPathAsArray(): array
{
if ($this->pathArray === null) {
if ($this->parent === null) {
@@ -124,10 +106,7 @@ abstract class AbstractNode implements \Countable
return $this->pathArray;
}
/**
* @return AbstractNode
*/
public function getParent()
public function getParent(): ?self
{
return $this->parent;
}
@@ -135,11 +114,9 @@ abstract class AbstractNode implements \Countable
/**
* Returns the percentage of classes that has been tested.
*
* @param bool $asString
*
* @return int
* @return int|string
*/
public function getTestedClassesPercent($asString = true)
public function getTestedClassesPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedClasses(),
@@ -151,11 +128,9 @@ abstract class AbstractNode implements \Countable
/**
* Returns the percentage of traits that has been tested.
*
* @param bool $asString
*
* @return int
* @return int|string
*/
public function getTestedTraitsPercent($asString = true)
public function getTestedTraitsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedTraits(),
@@ -167,11 +142,9 @@ abstract class AbstractNode implements \Countable
/**
* Returns the percentage of classes and traits that has been tested.
*
* @param bool $asString
*
* @return int
* @return int|string
*/
public function getTestedClassesAndTraitsPercent($asString = true)
public function getTestedClassesAndTraitsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedClassesAndTraits(),
@@ -183,11 +156,9 @@ abstract class AbstractNode implements \Countable
/**
* Returns the percentage of functions that has been tested.
*
* @param bool $asString
*
* @return int
* @return int|string
*/
public function getTestedFunctionsPercent($asString = true)
public function getTestedFunctionsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedFunctions(),
@@ -199,11 +170,9 @@ abstract class AbstractNode implements \Countable
/**
* Returns the percentage of methods that has been tested.
*
* @param bool $asString
*
* @return int
* @return int|string
*/
public function getTestedMethodsPercent($asString = true)
public function getTestedMethodsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedMethods(),
@@ -215,11 +184,9 @@ abstract class AbstractNode implements \Countable
/**
* Returns the percentage of functions and methods that has been tested.
*
* @param bool $asString
*
* @return int
* @return int|string
*/
public function getTestedFunctionsAndMethodsPercent($asString = true)
public function getTestedFunctionsAndMethodsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedFunctionsAndMethods(),
@@ -231,11 +198,9 @@ abstract class AbstractNode implements \Countable
/**
* Returns the percentage of executed lines.
*
* @param bool $asString
*
* @return int
* @return int|string
*/
public function getLineExecutedPercent($asString = true)
public function getLineExecutedPercent(bool $asString = true)
{
return Util::percent(
$this->getNumExecutedLines(),
@@ -246,159 +211,119 @@ abstract class AbstractNode implements \Countable
/**
* Returns the number of classes and traits.
*
* @return int
*/
public function getNumClassesAndTraits()
public function getNumClassesAndTraits(): int
{
return $this->getNumClasses() + $this->getNumTraits();
}
/**
* Returns the number of tested classes and traits.
*
* @return int
*/
public function getNumTestedClassesAndTraits()
public function getNumTestedClassesAndTraits(): int
{
return $this->getNumTestedClasses() + $this->getNumTestedTraits();
}
/**
* Returns the classes and traits of this node.
*
* @return array
*/
public function getClassesAndTraits()
public function getClassesAndTraits(): array
{
return \array_merge($this->getClasses(), $this->getTraits());
}
/**
* Returns the number of functions and methods.
*
* @return int
*/
public function getNumFunctionsAndMethods()
public function getNumFunctionsAndMethods(): int
{
return $this->getNumFunctions() + $this->getNumMethods();
}
/**
* Returns the number of tested functions and methods.
*
* @return int
*/
public function getNumTestedFunctionsAndMethods()
public function getNumTestedFunctionsAndMethods(): int
{
return $this->getNumTestedFunctions() + $this->getNumTestedMethods();
}
/**
* Returns the functions and methods of this node.
*
* @return array
*/
public function getFunctionsAndMethods()
public function getFunctionsAndMethods(): array
{
return \array_merge($this->getFunctions(), $this->getMethods());
}
/**
* Returns the classes of this node.
*
* @return array
*/
abstract public function getClasses();
abstract public function getClasses(): array;
/**
* Returns the traits of this node.
*
* @return array
*/
abstract public function getTraits();
abstract public function getTraits(): array;
/**
* Returns the functions of this node.
*
* @return array
*/
abstract public function getFunctions();
abstract public function getFunctions(): array;
/**
* Returns the LOC/CLOC/NCLOC of this node.
*
* @return array
*/
abstract public function getLinesOfCode();
abstract public function getLinesOfCode(): array;
/**
* Returns the number of executable lines.
*
* @return int
*/
abstract public function getNumExecutableLines();
abstract public function getNumExecutableLines(): int;
/**
* Returns the number of executed lines.
*
* @return int
*/
abstract public function getNumExecutedLines();
abstract public function getNumExecutedLines(): int;
/**
* Returns the number of classes.
*
* @return int
*/
abstract public function getNumClasses();
abstract public function getNumClasses(): int;
/**
* Returns the number of tested classes.
*
* @return int
*/
abstract public function getNumTestedClasses();
abstract public function getNumTestedClasses(): int;
/**
* Returns the number of traits.
*
* @return int
*/
abstract public function getNumTraits();
abstract public function getNumTraits(): int;
/**
* Returns the number of tested traits.
*
* @return int
*/
abstract public function getNumTestedTraits();
abstract public function getNumTestedTraits(): int;
/**
* Returns the number of methods.
*
* @return int
*/
abstract public function getNumMethods();
abstract public function getNumMethods(): int;
/**
* Returns the number of tested methods.
*
* @return int
*/
abstract public function getNumTestedMethods();
abstract public function getNumTestedMethods(): int;
/**
* Returns the number of functions.
*
* @return int
*/
abstract public function getNumFunctions();
abstract public function getNumFunctions(): int;
/**
* Returns the number of tested functions.
*
* @return int
*/
abstract public function getNumTestedFunctions();
abstract public function getNumTestedFunctions(): int;
}

View File

@@ -12,14 +12,9 @@ namespace SebastianBergmann\CodeCoverage\Node;
use SebastianBergmann\CodeCoverage\CodeCoverage;
class Builder
final class Builder
{
/**
* @param CodeCoverage $coverage
*
* @return Directory
*/
public function build(CodeCoverage $coverage)
public function build(CodeCoverage $coverage): Directory
{
$files = $coverage->getData();
$commonPath = $this->reducePaths($files);
@@ -38,13 +33,7 @@ class Builder
return $root;
}
/**
* @param Directory $root
* @param array $items
* @param array $tests
* @param bool $cacheTokens
*/
private function addItems(Directory $root, array $items, array $tests, $cacheTokens)
private function addItems(Directory $root, array $items, array $tests, bool $cacheTokens): void
{
foreach ($items as $key => $value) {
if (\substr($key, -2) == '/f') {
@@ -99,12 +88,8 @@ class Builder
* )
* )
* </code>
*
* @param array $files
*
* @return array
*/
private function buildDirectoryStructure($files)
private function buildDirectoryStructure(array $files): array
{
$result = [];
@@ -114,10 +99,10 @@ class Builder
$max = \count($path);
for ($i = 0; $i < $max; $i++) {
$type = '';
if ($i == ($max - 1)) {
$type = '/f';
} else {
$type = '';
}
$pointer = &$pointer[$path[$i] . $type];
@@ -165,12 +150,8 @@ class Builder
* )
* )
* </code>
*
* @param array $files
*
* @return string
*/
private function reducePaths(&$files)
private function reducePaths(array &$files): string
{
if (empty($files)) {
return '.';
@@ -179,7 +160,7 @@ class Builder
$commonPath = '';
$paths = \array_keys($files);
if (\count($files) == 1) {
if (\count($files) === 1) {
$commonPath = \dirname($paths[0]) . '/';
$files[\basename($paths[0])] = $files[$paths[0]];
@@ -194,7 +175,7 @@ class Builder
// strip phar:// prefixes
if (\strpos($paths[$i], 'phar://') === 0) {
$paths[$i] = \substr($paths[$i], 7);
$paths[$i] = \strtr($paths[$i], '/', DIRECTORY_SEPARATOR);
$paths[$i] = \str_replace('/', DIRECTORY_SEPARATOR, $paths[$i]);
}
$paths[$i] = \explode(DIRECTORY_SEPARATOR, $paths[$i]);

View File

@@ -15,7 +15,7 @@ use SebastianBergmann\CodeCoverage\InvalidArgumentException;
/**
* Represents a directory in the code coverage information tree.
*/
class Directory extends AbstractNode implements \IteratorAggregate
final class Directory extends AbstractNode implements \IteratorAggregate
{
/**
* @var AbstractNode[]
@@ -50,7 +50,7 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* @var array
*/
private $linesOfCode = null;
private $linesOfCode;
/**
* @var int
@@ -109,12 +109,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of files in/under this node.
*
* @return int
*/
public function count()
public function count(): int
{
if ($this->numFiles == -1) {
if ($this->numFiles === -1) {
$this->numFiles = 0;
foreach ($this->children as $child) {
@@ -127,10 +125,8 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns an iterator for this node.
*
* @return \RecursiveIteratorIterator
*/
public function getIterator()
public function getIterator(): \RecursiveIteratorIterator
{
return new \RecursiveIteratorIterator(
new Iterator($this),
@@ -140,12 +136,8 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Adds a new directory.
*
* @param string $name
*
* @return Directory
*/
public function addDirectory($name)
public function addDirectory(string $name): self
{
$directory = new self($name, $this);
@@ -158,24 +150,11 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Adds a new file.
*
* @param string $name
* @param array $coverageData
* @param array $testData
* @param bool $cacheTokens
*
* @return File
*
* @throws InvalidArgumentException
*/
public function addFile($name, array $coverageData, array $testData, $cacheTokens)
public function addFile(string $name, array $coverageData, array $testData, bool $cacheTokens): File
{
$file = new File(
$name,
$this,
$coverageData,
$testData,
$cacheTokens
);
$file = new File($name, $this, $coverageData, $testData, $cacheTokens);
$this->children[] = $file;
$this->files[] = &$this->children[\count($this->children) - 1];
@@ -188,40 +167,32 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the directories in this directory.
*
* @return array
*/
public function getDirectories()
public function getDirectories(): array
{
return $this->directories;
}
/**
* Returns the files in this directory.
*
* @return array
*/
public function getFiles()
public function getFiles(): array
{
return $this->files;
}
/**
* Returns the child nodes of this node.
*
* @return array
*/
public function getChildNodes()
public function getChildNodes(): array
{
return $this->children;
}
/**
* Returns the classes of this node.
*
* @return array
*/
public function getClasses()
public function getClasses(): array
{
if ($this->classes === null) {
$this->classes = [];
@@ -239,10 +210,8 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the traits of this node.
*
* @return array
*/
public function getTraits()
public function getTraits(): array
{
if ($this->traits === null) {
$this->traits = [];
@@ -260,10 +229,8 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the functions of this node.
*
* @return array
*/
public function getFunctions()
public function getFunctions(): array
{
if ($this->functions === null) {
$this->functions = [];
@@ -281,10 +248,8 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the LOC/CLOC/NCLOC of this node.
*
* @return array
*/
public function getLinesOfCode()
public function getLinesOfCode(): array
{
if ($this->linesOfCode === null) {
$this->linesOfCode = ['loc' => 0, 'cloc' => 0, 'ncloc' => 0];
@@ -303,12 +268,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of executable lines.
*
* @return int
*/
public function getNumExecutableLines()
public function getNumExecutableLines(): int
{
if ($this->numExecutableLines == -1) {
if ($this->numExecutableLines === -1) {
$this->numExecutableLines = 0;
foreach ($this->children as $child) {
@@ -321,12 +284,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of executed lines.
*
* @return int
*/
public function getNumExecutedLines()
public function getNumExecutedLines(): int
{
if ($this->numExecutedLines == -1) {
if ($this->numExecutedLines === -1) {
$this->numExecutedLines = 0;
foreach ($this->children as $child) {
@@ -339,12 +300,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of classes.
*
* @return int
*/
public function getNumClasses()
public function getNumClasses(): int
{
if ($this->numClasses == -1) {
if ($this->numClasses === -1) {
$this->numClasses = 0;
foreach ($this->children as $child) {
@@ -357,12 +316,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of tested classes.
*
* @return int
*/
public function getNumTestedClasses()
public function getNumTestedClasses(): int
{
if ($this->numTestedClasses == -1) {
if ($this->numTestedClasses === -1) {
$this->numTestedClasses = 0;
foreach ($this->children as $child) {
@@ -375,12 +332,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of traits.
*
* @return int
*/
public function getNumTraits()
public function getNumTraits(): int
{
if ($this->numTraits == -1) {
if ($this->numTraits === -1) {
$this->numTraits = 0;
foreach ($this->children as $child) {
@@ -393,12 +348,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of tested traits.
*
* @return int
*/
public function getNumTestedTraits()
public function getNumTestedTraits(): int
{
if ($this->numTestedTraits == -1) {
if ($this->numTestedTraits === -1) {
$this->numTestedTraits = 0;
foreach ($this->children as $child) {
@@ -411,12 +364,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of methods.
*
* @return int
*/
public function getNumMethods()
public function getNumMethods(): int
{
if ($this->numMethods == -1) {
if ($this->numMethods === -1) {
$this->numMethods = 0;
foreach ($this->children as $child) {
@@ -429,12 +380,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of tested methods.
*
* @return int
*/
public function getNumTestedMethods()
public function getNumTestedMethods(): int
{
if ($this->numTestedMethods == -1) {
if ($this->numTestedMethods === -1) {
$this->numTestedMethods = 0;
foreach ($this->children as $child) {
@@ -447,12 +396,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of functions.
*
* @return int
*/
public function getNumFunctions()
public function getNumFunctions(): int
{
if ($this->numFunctions == -1) {
if ($this->numFunctions === -1) {
$this->numFunctions = 0;
foreach ($this->children as $child) {
@@ -465,12 +412,10 @@ class Directory extends AbstractNode implements \IteratorAggregate
/**
* Returns the number of tested functions.
*
* @return int
*/
public function getNumTestedFunctions()
public function getNumTestedFunctions(): int
{
if ($this->numTestedFunctions == -1) {
if ($this->numTestedFunctions === -1) {
$this->numTestedFunctions = 0;
foreach ($this->children as $child) {

View File

@@ -10,12 +10,10 @@
namespace SebastianBergmann\CodeCoverage\Node;
use SebastianBergmann\CodeCoverage\InvalidArgumentException;
/**
* Represents a file in the code coverage information tree.
*/
class File extends AbstractNode
final class File extends AbstractNode
{
/**
* @var array
@@ -60,7 +58,7 @@ class File extends AbstractNode
/**
* @var int
*/
private $numClasses = null;
private $numClasses;
/**
* @var int
@@ -70,7 +68,7 @@ class File extends AbstractNode
/**
* @var int
*/
private $numTraits = null;
private $numTraits;
/**
* @var int
@@ -80,27 +78,17 @@ class File extends AbstractNode
/**
* @var int
*/
private $numMethods = null;
private $numMethods;
/**
* @var int
*/
private $numTestedMethods = null;
private $numTestedMethods;
/**
* @var int
*/
private $numTestedFunctions = null;
/**
* @var array
*/
private $startLines = [];
/**
* @var array
*/
private $endLines = [];
private $numTestedFunctions;
/**
* @var bool
@@ -108,25 +96,12 @@ class File extends AbstractNode
private $cacheTokens;
/**
* Constructor.
*
* @param string $name
* @param AbstractNode $parent
* @param array $coverageData
* @param array $testData
* @param bool $cacheTokens
*
* @throws InvalidArgumentException
* @var array
*/
public function __construct($name, AbstractNode $parent, array $coverageData, array $testData, $cacheTokens)
{
if (!\is_bool($cacheTokens)) {
throw InvalidArgumentException::create(
1,
'boolean'
);
}
private $codeUnitsByLine = [];
public function __construct(string $name, AbstractNode $parent, array $coverageData, array $testData, bool $cacheTokens)
{
parent::__construct($name, $parent);
$this->coverageData = $coverageData;
@@ -138,100 +113,80 @@ class File extends AbstractNode
/**
* Returns the number of files in/under this node.
*
* @return int
*/
public function count()
public function count(): int
{
return 1;
}
/**
* Returns the code coverage data of this node.
*
* @return array
*/
public function getCoverageData()
public function getCoverageData(): array
{
return $this->coverageData;
}
/**
* Returns the test data of this node.
*
* @return array
*/
public function getTestData()
public function getTestData(): array
{
return $this->testData;
}
/**
* Returns the classes of this node.
*
* @return array
*/
public function getClasses()
public function getClasses(): array
{
return $this->classes;
}
/**
* Returns the traits of this node.
*
* @return array
*/
public function getTraits()
public function getTraits(): array
{
return $this->traits;
}
/**
* Returns the functions of this node.
*
* @return array
*/
public function getFunctions()
public function getFunctions(): array
{
return $this->functions;
}
/**
* Returns the LOC/CLOC/NCLOC of this node.
*
* @return array
*/
public function getLinesOfCode()
public function getLinesOfCode(): array
{
return $this->linesOfCode;
}
/**
* Returns the number of executable lines.
*
* @return int
*/
public function getNumExecutableLines()
public function getNumExecutableLines(): int
{
return $this->numExecutableLines;
}
/**
* Returns the number of executed lines.
*
* @return int
*/
public function getNumExecutedLines()
public function getNumExecutedLines(): int
{
return $this->numExecutedLines;
}
/**
* Returns the number of classes.
*
* @return int
*/
public function getNumClasses()
public function getNumClasses(): int
{
if ($this->numClasses === null) {
$this->numClasses = 0;
@@ -252,20 +207,16 @@ class File extends AbstractNode
/**
* Returns the number of tested classes.
*
* @return int
*/
public function getNumTestedClasses()
public function getNumTestedClasses(): int
{
return $this->numTestedClasses;
}
/**
* Returns the number of traits.
*
* @return int
*/
public function getNumTraits()
public function getNumTraits(): int
{
if ($this->numTraits === null) {
$this->numTraits = 0;
@@ -286,20 +237,16 @@ class File extends AbstractNode
/**
* Returns the number of tested traits.
*
* @return int
*/
public function getNumTestedTraits()
public function getNumTestedTraits(): int
{
return $this->numTestedTraits;
}
/**
* Returns the number of methods.
*
* @return int
*/
public function getNumMethods()
public function getNumMethods(): int
{
if ($this->numMethods === null) {
$this->numMethods = 0;
@@ -326,10 +273,8 @@ class File extends AbstractNode
/**
* Returns the number of tested methods.
*
* @return int
*/
public function getNumTestedMethods()
public function getNumTestedMethods(): int
{
if ($this->numTestedMethods === null) {
$this->numTestedMethods = 0;
@@ -337,7 +282,7 @@ class File extends AbstractNode
foreach ($this->classes as $class) {
foreach ($class['methods'] as $method) {
if ($method['executableLines'] > 0 &&
$method['coverage'] == 100) {
$method['coverage'] === 100) {
$this->numTestedMethods++;
}
}
@@ -346,7 +291,7 @@ class File extends AbstractNode
foreach ($this->traits as $trait) {
foreach ($trait['methods'] as $method) {
if ($method['executableLines'] > 0 &&
$method['coverage'] == 100) {
$method['coverage'] === 100) {
$this->numTestedMethods++;
}
}
@@ -358,27 +303,23 @@ class File extends AbstractNode
/**
* Returns the number of functions.
*
* @return int
*/
public function getNumFunctions()
public function getNumFunctions(): int
{
return \count($this->functions);
}
/**
* Returns the number of tested functions.
*
* @return int
*/
public function getNumTestedFunctions()
public function getNumTestedFunctions(): int
{
if ($this->numTestedFunctions === null) {
$this->numTestedFunctions = 0;
foreach ($this->functions as $function) {
if ($function['executableLines'] > 0 &&
$function['coverage'] == 100) {
$function['coverage'] === 100) {
$this->numTestedFunctions++;
}
}
@@ -387,119 +328,45 @@ class File extends AbstractNode
return $this->numTestedFunctions;
}
/**
* Calculates coverage statistics for the file.
*/
protected function calculateStatistics()
private function calculateStatistics(): void
{
$classStack = $functionStack = [];
if ($this->cacheTokens) {
$tokens = \PHP_Token_Stream_CachingFactory::get($this->getPath());
} else {
$tokens = new \PHP_Token_Stream($this->getPath());
}
$this->linesOfCode = $tokens->getLinesOfCode();
foreach (\range(1, $this->linesOfCode['loc']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [];
}
$this->processClasses($tokens);
$this->processTraits($tokens);
$this->processFunctions($tokens);
$this->linesOfCode = $tokens->getLinesOfCode();
unset($tokens);
for ($lineNumber = 1; $lineNumber <= $this->linesOfCode['loc']; $lineNumber++) {
if (isset($this->startLines[$lineNumber])) {
// Start line of a class.
if (isset($this->startLines[$lineNumber]['className'])) {
if (isset($currentClass)) {
$classStack[] = &$currentClass;
}
$currentClass = &$this->startLines[$lineNumber];
} // Start line of a trait.
elseif (isset($this->startLines[$lineNumber]['traitName'])) {
$currentTrait = &$this->startLines[$lineNumber];
} // Start line of a method.
elseif (isset($this->startLines[$lineNumber]['methodName'])) {
$currentMethod = &$this->startLines[$lineNumber];
} // Start line of a function.
elseif (isset($this->startLines[$lineNumber]['functionName'])) {
if (isset($currentFunction)) {
$functionStack[] = &$currentFunction;
}
$currentFunction = &$this->startLines[$lineNumber];
}
}
foreach (\range(1, $this->linesOfCode['loc']) as $lineNumber) {
if (isset($this->coverageData[$lineNumber])) {
if (isset($currentClass)) {
$currentClass['executableLines']++;
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
$codeUnit['executableLines']++;
}
if (isset($currentTrait)) {
$currentTrait['executableLines']++;
}
if (isset($currentMethod)) {
$currentMethod['executableLines']++;
}
if (isset($currentFunction)) {
$currentFunction['executableLines']++;
}
unset($codeUnit);
$this->numExecutableLines++;
if (\count($this->coverageData[$lineNumber]) > 0) {
if (isset($currentClass)) {
$currentClass['executedLines']++;
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
$codeUnit['executedLines']++;
}
if (isset($currentTrait)) {
$currentTrait['executedLines']++;
}
if (isset($currentMethod)) {
$currentMethod['executedLines']++;
}
if (isset($currentFunction)) {
$currentFunction['executedLines']++;
}
unset($codeUnit);
$this->numExecutedLines++;
}
}
if (isset($this->endLines[$lineNumber])) {
// End line of a class.
if (isset($this->endLines[$lineNumber]['className'])) {
unset($currentClass);
if ($classStack) {
\end($classStack);
$key = \key($classStack);
$currentClass = &$classStack[$key];
unset($classStack[$key]);
}
} // End line of a trait.
elseif (isset($this->endLines[$lineNumber]['traitName'])) {
unset($currentTrait);
} // End line of a method.
elseif (isset($this->endLines[$lineNumber]['methodName'])) {
unset($currentMethod);
} // End line of a function.
elseif (isset($this->endLines[$lineNumber]['functionName'])) {
unset($currentFunction);
if ($functionStack) {
\end($functionStack);
$key = \key($functionStack);
$currentFunction = &$functionStack[$key];
unset($functionStack[$key]);
}
}
}
}
foreach ($this->traits as &$trait) {
@@ -519,11 +386,13 @@ class File extends AbstractNode
$trait['ccn'] += $method['ccn'];
}
unset($method);
if ($trait['executableLines'] > 0) {
$trait['coverage'] = ($trait['executedLines'] /
$trait['executableLines']) * 100;
if ($trait['coverage'] == 100) {
if ($trait['coverage'] === 100) {
$this->numTestedClasses++;
}
} else {
@@ -536,6 +405,8 @@ class File extends AbstractNode
);
}
unset($trait);
foreach ($this->classes as &$class) {
foreach ($class['methods'] as &$method) {
if ($method['executableLines'] > 0) {
@@ -553,11 +424,13 @@ class File extends AbstractNode
$class['ccn'] += $method['ccn'];
}
unset($method);
if ($class['executableLines'] > 0) {
$class['coverage'] = ($class['executedLines'] /
$class['executableLines']) * 100;
if ($class['coverage'] == 100) {
if ($class['coverage'] === 100) {
$this->numTestedClasses++;
}
} else {
@@ -570,6 +443,8 @@ class File extends AbstractNode
);
}
unset($class);
foreach ($this->functions as &$function) {
if ($function['executableLines'] > 0) {
$function['coverage'] = ($function['executedLines'] /
@@ -578,7 +453,7 @@ class File extends AbstractNode
$function['coverage'] = 100;
}
if ($function['coverage'] == 100) {
if ($function['coverage'] === 100) {
$this->numTestedFunctions++;
}
@@ -589,17 +464,16 @@ class File extends AbstractNode
}
}
/**
* @param \PHP_Token_Stream $tokens
*/
protected function processClasses(\PHP_Token_Stream $tokens)
private function processClasses(\PHP_Token_Stream $tokens): void
{
$classes = $tokens->getClasses();
unset($tokens);
$link = $this->getId() . '.html#';
$link = $this->getId() . '.html#';
foreach ($classes as $className => $class) {
if (\strpos($className, 'anonymous') === 0) {
continue;
}
if (!empty($class['package']['namespace'])) {
$className = $class['package']['namespace'] . '\\' . $className;
}
@@ -617,27 +491,27 @@ class File extends AbstractNode
'link' => $link . $class['startLine']
];
$this->startLines[$class['startLine']] = &$this->classes[$className];
$this->endLines[$class['endLine']] = &$this->classes[$className];
foreach ($class['methods'] as $methodName => $method) {
if (\strpos($methodName, 'anonymous') === 0) {
continue;
}
$this->classes[$className]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);
$this->startLines[$method['startLine']] = &$this->classes[$className]['methods'][$methodName];
$this->endLines[$method['endLine']] = &$this->classes[$className]['methods'][$methodName];
foreach (\range($method['startLine'], $method['endLine']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [
&$this->classes[$className],
&$this->classes[$className]['methods'][$methodName]
];
}
}
}
}
/**
* @param \PHP_Token_Stream $tokens
*/
protected function processTraits(\PHP_Token_Stream $tokens)
private function processTraits(\PHP_Token_Stream $tokens): void
{
$traits = $tokens->getTraits();
unset($tokens);
$link = $this->getId() . '.html#';
$link = $this->getId() . '.html#';
foreach ($traits as $traitName => $trait) {
$this->traits[$traitName] = [
@@ -653,29 +527,33 @@ class File extends AbstractNode
'link' => $link . $trait['startLine']
];
$this->startLines[$trait['startLine']] = &$this->traits[$traitName];
$this->endLines[$trait['endLine']] = &$this->traits[$traitName];
foreach ($trait['methods'] as $methodName => $method) {
if (\strpos($methodName, 'anonymous') === 0) {
continue;
}
$this->traits[$traitName]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);
$this->startLines[$method['startLine']] = &$this->traits[$traitName]['methods'][$methodName];
$this->endLines[$method['endLine']] = &$this->traits[$traitName]['methods'][$methodName];
foreach (\range($method['startLine'], $method['endLine']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [
&$this->traits[$traitName],
&$this->traits[$traitName]['methods'][$methodName]
];
}
}
}
}
/**
* @param \PHP_Token_Stream $tokens
*/
protected function processFunctions(\PHP_Token_Stream $tokens)
private function processFunctions(\PHP_Token_Stream $tokens): void
{
$functions = $tokens->getFunctions();
unset($tokens);
$link = $this->getId() . '.html#';
$link = $this->getId() . '.html#';
foreach ($functions as $functionName => $function) {
if (\strpos($functionName, 'anonymous') === 0) {
continue;
}
$this->functions[$functionName] = [
'functionName' => $functionName,
'signature' => $function['signature'],
@@ -688,24 +566,16 @@ class File extends AbstractNode
'link' => $link . $function['startLine']
];
$this->startLines[$function['startLine']] = &$this->functions[$functionName];
$this->endLines[$function['endLine']] = &$this->functions[$functionName];
foreach (\range($function['startLine'], $function['endLine']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [&$this->functions[$functionName]];
}
}
}
/**
* Calculates the Change Risk Anti-Patterns (CRAP) index for a unit of code
* based on its cyclomatic complexity and percentage of code coverage.
*
* @param int $ccn
* @param float $coverage
*
* @return string
*/
protected function crap($ccn, $coverage)
private function crap(int $ccn, float $coverage): string
{
if ($coverage == 0) {
return (string) (\pow($ccn, 2) + $ccn);
if ($coverage === 0) {
return (string) ($ccn ** 2 + $ccn);
}
if ($coverage >= 95) {
@@ -714,18 +584,11 @@ class File extends AbstractNode
return \sprintf(
'%01.2F',
\pow($ccn, 2) * \pow(1 - $coverage / 100, 3) + $ccn
$ccn ** 2 * (1 - $coverage / 100) ** 3 + $ccn
);
}
/**
* @param string $methodName
* @param array $method
* @param string $link
*
* @return array
*/
private function newMethod($methodName, array $method, $link)
private function newMethod(string $methodName, array $method, string $link): array
{
return [
'methodName' => $methodName,

View File

@@ -13,7 +13,7 @@ namespace SebastianBergmann\CodeCoverage\Node;
/**
* Recursive iterator for node object graphs.
*/
class Iterator implements \RecursiveIterator
final class Iterator implements \RecursiveIterator
{
/**
* @var int
@@ -25,9 +25,6 @@ class Iterator implements \RecursiveIterator
*/
private $nodes;
/**
* @param Directory $node
*/
public function __construct(Directory $node)
{
$this->nodes = $node->getChildNodes();
@@ -36,37 +33,31 @@ class Iterator implements \RecursiveIterator
/**
* Rewinds the Iterator to the first element.
*/
public function rewind()
public function rewind(): void
{
$this->position = 0;
}
/**
* Checks if there is a current element after calls to rewind() or next().
*
* @return bool
*/
public function valid()
public function valid(): bool
{
return $this->position < \count($this->nodes);
}
/**
* Returns the key of the current element.
*
* @return int
*/
public function key()
public function key(): int
{
return $this->position;
}
/**
* Returns the current element.
*
* @return \PHPUnit_Framework_Test
*/
public function current()
public function current(): AbstractNode
{
return $this->valid() ? $this->nodes[$this->position] : null;
}
@@ -74,7 +65,7 @@ class Iterator implements \RecursiveIterator
/**
* Moves forward to next element.
*/
public function next()
public function next(): void
{
$this->position++;
}
@@ -84,11 +75,9 @@ class Iterator implements \RecursiveIterator
*
* @return Iterator
*/
public function getChildren()
public function getChildren(): self
{
return new self(
$this->nodes[$this->position]
);
return new self($this->nodes[$this->position]);
}
/**
@@ -96,7 +85,7 @@ class Iterator implements \RecursiveIterator
*
* @return bool
*/
public function hasChildren()
public function hasChildren(): bool
{
return $this->nodes[$this->position] instanceof Directory;
}

View File

@@ -17,18 +17,12 @@ use SebastianBergmann\CodeCoverage\RuntimeException;
/**
* Generates a Clover XML logfile from a code coverage object.
*/
class Clover
final class Clover
{
/**
* @param CodeCoverage $coverage
* @param string $target
* @param string $name
*
* @return string
*
* @throws \SebastianBergmann\CodeCoverage\RuntimeException
* @throws \RuntimeException
*/
public function process(CodeCoverage $coverage, $target = null, $name = null)
public function process(CodeCoverage $coverage, ?string $target = null, ?string $name = null): string
{
$xmlDocument = new \DOMDocument('1.0', 'UTF-8');
$xmlDocument->formatOutput = true;
@@ -48,7 +42,6 @@ class Clover
$packages = [];
$report = $coverage->getReport();
unset($coverage);
foreach ($report as $item) {
if (!$item instanceof File) {
@@ -60,10 +53,10 @@ class Clover
$xmlFile = $xmlDocument->createElement('file');
$xmlFile->setAttribute('name', $item->getPath());
$classes = $item->getClassesAndTraits();
$coverage = $item->getCoverageData();
$lines = [];
$namespace = 'global';
$classes = $item->getClassesAndTraits();
$coverageData = $item->getCoverageData();
$lines = [];
$namespace = 'global';
foreach ($classes as $className => $class) {
$classStatements = 0;
@@ -87,8 +80,8 @@ class Clover
$methodCount = 0;
foreach (\range($method['startLine'], $method['endLine']) as $line) {
if (isset($coverage[$line]) && ($coverage[$line] !== null)) {
$methodCount = \max($methodCount, \count($coverage[$line]));
if (isset($coverageData[$line]) && ($coverageData[$line] !== null)) {
$methodCount = \max($methodCount, \count($coverageData[$line]));
}
}
@@ -153,7 +146,7 @@ class Clover
$xmlClass->appendChild($xmlMetrics);
}
foreach ($coverage as $line => $data) {
foreach ($coverageData as $line => $data) {
if ($data === null || isset($lines[$line])) {
continue;
}
@@ -206,7 +199,7 @@ class Clover
$xmlMetrics->setAttribute('coveredelements', $item->getNumTestedMethods() + $item->getNumExecutedLines() /* + coveredconditionals */);
$xmlFile->appendChild($xmlMetrics);
if ($namespace == 'global') {
if ($namespace === 'global') {
$xmlProject->appendChild($xmlFile);
} else {
if (!isset($packages[$namespace])) {
@@ -242,8 +235,8 @@ class Clover
$buffer = $xmlDocument->saveXML();
if ($target !== null) {
if (!\is_dir(\dirname($target))) {
\mkdir(\dirname($target), 0777, true);
if (!$this->createDirectory(\dirname($target))) {
throw new \RuntimeException(\sprintf('Directory "%s" was not created', \dirname($target)));
}
if (@\file_put_contents($target, $buffer) === false) {
@@ -258,4 +251,9 @@ class Clover
return $buffer;
}
private function createDirectory(string $directory): bool
{
return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory));
}
}

View File

@@ -11,42 +11,25 @@
namespace SebastianBergmann\CodeCoverage\Report;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\InvalidArgumentException;
use SebastianBergmann\CodeCoverage\Node\File;
use SebastianBergmann\CodeCoverage\RuntimeException;
class Crap4j
final class Crap4j
{
/**
* @var int
*/
private $threshold;
/**
* @param int $threshold
*/
public function __construct($threshold = 30)
public function __construct(int $threshold = 30)
{
if (!\is_int($threshold)) {
throw InvalidArgumentException::create(
1,
'integer'
);
}
$this->threshold = $threshold;
}
/**
* @param CodeCoverage $coverage
* @param string $target
* @param string $name
*
* @return string
*
* @throws \SebastianBergmann\CodeCoverage\RuntimeException
* @throws \RuntimeException
*/
public function process(CodeCoverage $coverage, $target = null, $name = null)
public function process(CodeCoverage $coverage, ?string $target = null, ?string $name = null): string
{
$document = new \DOMDocument('1.0', 'UTF-8');
$document->formatOutput = true;
@@ -120,10 +103,10 @@ class Crap4j
$stats->appendChild($document->createElement('crapLoad', \round($fullCrapLoad)));
$stats->appendChild($document->createElement('totalCrap', $fullCrap));
$crapMethodPercent = 0;
if ($fullMethodCount > 0) {
$crapMethodPercent = $this->roundValue((100 * $fullCrapMethodCount) / $fullMethodCount);
} else {
$crapMethodPercent = 0;
}
$stats->appendChild($document->createElement('crapMethodPercent', $crapMethodPercent));
@@ -134,8 +117,8 @@ class Crap4j
$buffer = $document->saveXML();
if ($target !== null) {
if (!\is_dir(\dirname($target))) {
\mkdir(\dirname($target), 0777, true);
if (!$this->createDirectory(\dirname($target))) {
throw new \RuntimeException(\sprintf('Directory "%s" was not created', \dirname($target)));
}
if (@\file_put_contents($target, $buffer) === false) {
@@ -158,7 +141,7 @@ class Crap4j
*
* @return float
*/
private function getCrapLoad($crapValue, $cyclomaticComplexity, $coveragePercent)
private function getCrapLoad($crapValue, $cyclomaticComplexity, $coveragePercent): float
{
$crapLoad = 0;
@@ -175,8 +158,13 @@ class Crap4j
*
* @return float
*/
private function roundValue($value)
private function roundValue($value): float
{
return \round($value, 2);
}
private function createDirectory(string $directory): bool
{
return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory));
}
}

View File

@@ -17,7 +17,7 @@ use SebastianBergmann\CodeCoverage\RuntimeException;
/**
* Generates an HTML report from a code coverage object.
*/
class Facade
final class Facade
{
/**
* @var string
@@ -39,14 +39,7 @@ class Facade
*/
private $highLowerBound;
/**
* Constructor.
*
* @param int $lowUpperBound
* @param int $highLowerBound
* @param string $generator
*/
public function __construct($lowUpperBound = 50, $highLowerBound = 90, $generator = '')
public function __construct(int $lowUpperBound = 50, int $highLowerBound = 90, string $generator = '')
{
$this->generator = $generator;
$this->highLowerBound = $highLowerBound;
@@ -55,14 +48,14 @@ class Facade
}
/**
* @param CodeCoverage $coverage
* @param string $target
* @throws RuntimeException
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public function process(CodeCoverage $coverage, $target)
public function process(CodeCoverage $coverage, string $target): void
{
$target = $this->getDirectory($target);
$report = $coverage->getReport();
unset($coverage);
if (!isset($_SERVER['REQUEST_TIME'])) {
$_SERVER['REQUEST_TIME'] = \time();
@@ -101,8 +94,8 @@ class Facade
$id = $node->getId();
if ($node instanceof DirectoryNode) {
if (!\file_exists($target . $id)) {
\mkdir($target . $id, 0777, true);
if (!$this->createDirectory($target . $id)) {
throw new \RuntimeException(\sprintf('Directory "%s" was not created', $target . $id));
}
$directory->render($node, $target . $id . '/index.html');
@@ -110,8 +103,8 @@ class Facade
} else {
$dir = \dirname($target . $id);
if (!\file_exists($dir)) {
\mkdir($dir, 0777, true);
if (!$this->createDirectory($dir)) {
throw new \RuntimeException(\sprintf('Directory "%s" was not created', $dir));
}
$file->render($node, $target . $id . '.html');
@@ -122,9 +115,9 @@ class Facade
}
/**
* @param string $target
* @throws RuntimeException
*/
private function copyFiles($target)
private function copyFiles(string $target): void
{
$dir = $this->getDirectory($target . '.css');
@@ -140,6 +133,7 @@ class Facade
\copy($this->templatePath . 'css/nv.d3.min.css', $dir . 'nv.d3.min.css');
\copy($this->templatePath . 'css/style.css', $dir . 'style.css');
\copy($this->templatePath . 'css/custom.css', $dir . 'custom.css');
$dir = $this->getDirectory($target . '.fonts');
\copy($this->templatePath . 'fonts/glyphicons-halflings-regular.eot', $dir . 'glyphicons-halflings-regular.eot');
@@ -160,31 +154,28 @@ class Facade
}
/**
* @param string $directory
*
* @return string
*
* @throws RuntimeException
*/
private function getDirectory($directory)
private function getDirectory(string $directory): string
{
if (\substr($directory, -1, 1) != DIRECTORY_SEPARATOR) {
$directory .= DIRECTORY_SEPARATOR;
}
if (\is_dir($directory)) {
return $directory;
if (!$this->createDirectory($directory)) {
throw new RuntimeException(
\sprintf(
'Directory "%s" does not exist.',
$directory
)
);
}
if (@\mkdir($directory, 0777, true)) {
return $directory;
}
return $directory;
}
throw new RuntimeException(
\sprintf(
'Directory "%s" does not exist.',
$directory
)
);
private function createDirectory(string $directory): bool
{
return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory));
}
}

View File

@@ -51,16 +51,7 @@ abstract class Renderer
*/
protected $version;
/**
* Constructor.
*
* @param string $templatePath
* @param string $generator
* @param string $date
* @param int $lowUpperBound
* @param int $highLowerBound
*/
public function __construct($templatePath, $generator, $date, $lowUpperBound, $highLowerBound)
public function __construct(string $templatePath, string $generator, string $date, int $lowUpperBound, int $highLowerBound)
{
$this->templatePath = $templatePath;
$this->generator = $generator;
@@ -70,13 +61,7 @@ abstract class Renderer
$this->version = Version::id();
}
/**
* @param \Text_Template $template
* @param array $data
*
* @return string
*/
protected function renderItemTemplate(\Text_Template $template, array $data)
protected function renderItemTemplate(\Text_Template $template, array $data): string
{
$numSeparator = '&nbsp;/&nbsp;';
@@ -130,8 +115,8 @@ abstract class Renderer
$template->setVar(
[
'icon' => isset($data['icon']) ? $data['icon'] : '',
'crap' => isset($data['crap']) ? $data['crap'] : '',
'icon' => $data['icon'] ?? '',
'crap' => $data['crap'] ?? '',
'name' => $data['name'],
'lines_bar' => $linesBar,
'lines_executed_percent' => $data['linesExecutedPercentAsString'],
@@ -142,7 +127,7 @@ abstract class Renderer
'methods_level' => $methodsLevel,
'methods_number' => $methodsNumber,
'classes_bar' => $classesBar,
'classes_tested_percent' => isset($data['testedClassesPercentAsString']) ? $data['testedClassesPercentAsString'] : '',
'classes_tested_percent' => $data['testedClassesPercentAsString'] ?? '',
'classes_level' => $classesLevel,
'classes_number' => $classesNumber
]
@@ -151,11 +136,7 @@ abstract class Renderer
return $template->render();
}
/**
* @param \Text_Template $template
* @param AbstractNode $node
*/
protected function setCommonTemplateVariables(\Text_Template $template, AbstractNode $node)
protected function setCommonTemplateVariables(\Text_Template $template, AbstractNode $node): void
{
$template->setVar(
[
@@ -173,7 +154,7 @@ abstract class Renderer
);
}
protected function getBreadcrumbs(AbstractNode $node)
protected function getBreadcrumbs(AbstractNode $node): string
{
$breadcrumbs = '';
$path = $node->getPathAsArray();
@@ -202,7 +183,7 @@ abstract class Renderer
return $breadcrumbs;
}
protected function getActiveBreadcrumb(AbstractNode $node)
protected function getActiveBreadcrumb(AbstractNode $node): string
{
$buffer = \sprintf(
' <li class="active">%s</li>' . "\n",
@@ -216,7 +197,7 @@ abstract class Renderer
return $buffer;
}
protected function getInactiveBreadcrumb(AbstractNode $node, $pathToRoot)
protected function getInactiveBreadcrumb(AbstractNode $node, string $pathToRoot): string
{
return \sprintf(
' <li><a href="%sindex.html">%s</a></li>' . "\n",
@@ -225,12 +206,12 @@ abstract class Renderer
);
}
protected function getPathToRoot(AbstractNode $node)
protected function getPathToRoot(AbstractNode $node): string
{
$id = $node->getId();
$depth = \substr_count($id, '/');
if ($id != 'index' &&
if ($id !== 'index' &&
$node instanceof DirectoryNode) {
$depth++;
}
@@ -238,7 +219,7 @@ abstract class Renderer
return \str_repeat('../', $depth);
}
protected function getCoverageBar($percent)
protected function getCoverageBar(float $percent): string
{
$level = $this->getColorLevel($percent);
@@ -253,27 +234,21 @@ abstract class Renderer
return $template->render();
}
/**
* @param int $percent
*
* @return string
*/
protected function getColorLevel($percent)
protected function getColorLevel(float $percent): string
{
if ($percent <= $this->lowUpperBound) {
return 'danger';
} elseif ($percent > $this->lowUpperBound &&
}
if ($percent > $this->lowUpperBound &&
$percent < $this->highLowerBound) {
return 'warning';
} else {
return 'success';
}
return 'success';
}
/**
* @return string
*/
private function getRuntimeString()
private function getRuntimeString(): string
{
$runtime = new Runtime;

View File

@@ -16,15 +16,13 @@ use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
/**
* Renders the dashboard for a directory node.
*/
class Dashboard extends Renderer
final class Dashboard extends Renderer
{
/**
* @param DirectoryNode $node
* @param string $file
*
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public function render(DirectoryNode $node, $file)
public function render(DirectoryNode $node, string $file)
{
$classes = $node->getClassesAndTraits();
$template = new \Text_Template(
@@ -59,13 +57,8 @@ class Dashboard extends Renderer
/**
* Returns the data for the Class/Method Complexity charts.
*
* @param array $classes
* @param string $baseLink
*
* @return array
*/
protected function complexity(array $classes, $baseLink)
protected function complexity(array $classes, string $baseLink): array
{
$result = ['class' => [], 'method' => []];
@@ -105,12 +98,8 @@ class Dashboard extends Renderer
/**
* Returns the data for the Class / Method Coverage Distribution chart.
*
* @param array $classes
*
* @return array
*/
protected function coverageDistribution(array $classes)
protected function coverageDistribution(array $classes): array
{
$result = [
'class' => [
@@ -175,13 +164,8 @@ class Dashboard extends Renderer
/**
* Returns the classes / methods with insufficient coverage.
*
* @param array $classes
* @param string $baseLink
*
* @return array
*/
protected function insufficientCoverage(array $classes, $baseLink)
protected function insufficientCoverage(array $classes, string $baseLink): array
{
$leastTestedClasses = [];
$leastTestedMethods = [];
@@ -218,7 +202,7 @@ class Dashboard extends Renderer
}
foreach ($leastTestedMethods as $methodName => $coverage) {
list($class, $method) = \explode('::', $methodName);
[$class, $method] = \explode('::', $methodName);
$result['method'] .= \sprintf(
' <tr><td><a href="%s"><abbr title="%s">%s</abbr></a></td><td class="text-right">%d%%</td></tr>' . "\n",
@@ -234,13 +218,8 @@ class Dashboard extends Renderer
/**
* Returns the project risks according to the CRAP index.
*
* @param array $classes
* @param string $baseLink
*
* @return array
*/
protected function projectRisks(array $classes, $baseLink)
protected function projectRisks(array $classes, string $baseLink): array
{
$classRisks = [];
$methodRisks = [];
@@ -248,12 +227,11 @@ class Dashboard extends Renderer
foreach ($classes as $className => $class) {
foreach ($class['methods'] as $methodName => $method) {
if ($method['coverage'] < $this->highLowerBound &&
$method['ccn'] > 1) {
if ($method['coverage'] < $this->highLowerBound && $method['ccn'] > 1) {
$key = $methodName;
if ($className !== '*') {
$key = $className . '::' . $methodName;
} else {
$key = $methodName;
}
$methodRisks[$key] = $method['crap'];
@@ -279,7 +257,7 @@ class Dashboard extends Renderer
}
foreach ($methodRisks as $methodName => $crap) {
list($class, $method) = \explode('::', $methodName);
[$class, $method] = \explode('::', $methodName);
$result['method'] .= \sprintf(
' <tr><td><a href="%s"><abbr title="%s">%s</abbr></a></td><td class="text-right">%d</td></tr>' . "\n",
@@ -293,7 +271,7 @@ class Dashboard extends Renderer
return $result;
}
protected function getActiveBreadcrumb(AbstractNode $node)
protected function getActiveBreadcrumb(AbstractNode $node): string
{
return \sprintf(
' <li><a href="index.html">%s</a></li>' . "\n" .

View File

@@ -16,13 +16,13 @@ use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
/**
* Renders a directory node.
*/
class Directory extends Renderer
final class Directory extends Renderer
{
/**
* @param DirectoryNode $node
* @param string $file
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public function render(DirectoryNode $node, $file)
public function render(DirectoryNode $node, string $file): void
{
$template = new \Text_Template($this->templatePath . 'directory.html', '{{', '}}');
@@ -48,13 +48,7 @@ class Directory extends Renderer
$template->renderTo($file);
}
/**
* @param Node $node
* @param bool $total
*
* @return string
*/
protected function renderItem(Node $node, $total = false)
protected function renderItem(Node $node, bool $total = false): string
{
$data = [
'numClasses' => $node->getNumClassesAndTraits(),

View File

@@ -16,42 +16,17 @@ use SebastianBergmann\CodeCoverage\Util;
/**
* Renders a file node.
*/
class File extends Renderer
final class File extends Renderer
{
/**
* @var int
*/
private $htmlspecialcharsFlags;
private $htmlSpecialCharsFlags = ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE;
/**
* Constructor.
*
* @param string $templatePath
* @param string $generator
* @param string $date
* @param int $lowUpperBound
* @param int $highLowerBound
* @throws \RuntimeException
*/
public function __construct($templatePath, $generator, $date, $lowUpperBound, $highLowerBound)
{
parent::__construct(
$templatePath,
$generator,
$date,
$lowUpperBound,
$highLowerBound
);
$this->htmlspecialcharsFlags = ENT_COMPAT;
$this->htmlspecialcharsFlags = $this->htmlspecialcharsFlags | ENT_HTML401 | ENT_SUBSTITUTE;
}
/**
* @param FileNode $node
* @param string $file
*/
public function render(FileNode $node, $file)
public function render(FileNode $node, string $file): void
{
$template = new \Text_Template($this->templatePath . 'file.html', '{{', '}}');
@@ -67,12 +42,7 @@ class File extends Renderer
$template->renderTo($file);
}
/**
* @param FileNode $node
*
* @return string
*/
protected function renderItems(FileNode $node)
protected function renderItems(FileNode $node): string
{
$template = new \Text_Template($this->templatePath . 'file_item.html', '{{', '}}');
@@ -122,14 +92,7 @@ class File extends Renderer
return $items;
}
/**
* @param array $items
* @param \Text_Template $template
* @param \Text_Template $methodItemTemplate
*
* @return string
*/
protected function renderTraitOrClassItems(array $items, \Text_Template $template, \Text_Template $methodItemTemplate)
protected function renderTraitOrClassItems(array $items, \Text_Template $template, \Text_Template $methodItemTemplate): string
{
$buffer = '';
@@ -183,8 +146,7 @@ class File extends Renderer
'numExecutableLines' => $item['executableLines'],
'testedMethodsPercent' => Util::percent(
$numTestedMethods,
$numMethods,
false
$numMethods
),
'testedMethodsPercentAsString' => Util::percent(
$numTestedMethods,
@@ -193,8 +155,7 @@ class File extends Renderer
),
'testedClassesPercent' => Util::percent(
$numTestedMethods == $numMethods ? 1 : 0,
1,
false
1
),
'testedClassesPercentAsString' => Util::percent(
$numTestedMethods == $numMethods ? 1 : 0,
@@ -217,13 +178,7 @@ class File extends Renderer
return $buffer;
}
/**
* @param array $functions
* @param \Text_Template $template
*
* @return string
*/
protected function renderFunctionItems(array $functions, \Text_Template $template)
protected function renderFunctionItems(array $functions, \Text_Template $template): string
{
if (empty($functions)) {
return '';
@@ -241,12 +196,7 @@ class File extends Renderer
return $buffer;
}
/**
* @param \Text_Template $template
*
* @return string
*/
protected function renderFunctionOrMethodItem(\Text_Template $template, array $item, $indent = '')
protected function renderFunctionOrMethodItem(\Text_Template $template, array $item, string $indent = ''): string
{
$numMethods = 0;
$numTestedMethods = 0;
@@ -266,15 +216,14 @@ class File extends Renderer
'%s<a href="#%d"><abbr title="%s">%s</abbr></a>',
$indent,
$item['startLine'],
\htmlspecialchars($item['signature']),
isset($item['functionName']) ? $item['functionName'] : $item['methodName']
\htmlspecialchars($item['signature'], $this->htmlSpecialCharsFlags),
$item['functionName'] ?? $item['methodName']
),
'numMethods' => $numMethods,
'numTestedMethods' => $numTestedMethods,
'linesExecutedPercent' => Util::percent(
$item['executedLines'],
$item['executableLines'],
false
$item['executableLines']
),
'linesExecutedPercentAsString' => Util::percent(
$item['executedLines'],
@@ -285,8 +234,7 @@ class File extends Renderer
'numExecutableLines' => $item['executableLines'],
'testedMethodsPercent' => Util::percent(
$numTestedMethods,
1,
false
1
),
'testedMethodsPercentAsString' => Util::percent(
$numTestedMethods,
@@ -303,7 +251,7 @@ class File extends Renderer
*
* @return string
*/
protected function renderSource(FileNode $node)
protected function renderSource(FileNode $node): string
{
$coverageData = $node->getCoverageData();
$testData = $node->getTestData();
@@ -384,7 +332,7 @@ class File extends Renderer
$popoverContent .= \sprintf(
'<li%s>%s</li>',
$testCSS,
\htmlspecialchars($test)
\htmlspecialchars($test, $this->htmlSpecialCharsFlags)
);
}
@@ -393,14 +341,14 @@ class File extends Renderer
}
}
$popover = '';
if (!empty($popoverTitle)) {
$popover = \sprintf(
' data-title="%s" data-content="%s" data-placement="bottom" data-html="true"',
$popoverTitle,
\htmlspecialchars($popoverContent)
\htmlspecialchars($popoverContent, $this->htmlSpecialCharsFlags)
);
} else {
$popover = '';
}
$lines .= \sprintf(
@@ -424,7 +372,7 @@ class File extends Renderer
*
* @return array
*/
protected function loadFile($file)
protected function loadFile($file): array
{
$buffer = \file_get_contents($file);
$tokens = \token_get_all($buffer);
@@ -440,26 +388,26 @@ class File extends Renderer
if ($token === '"' && $tokens[$j - 1] !== '\\') {
$result[$i] .= \sprintf(
'<span class="string">%s</span>',
\htmlspecialchars($token)
\htmlspecialchars($token, $this->htmlSpecialCharsFlags)
);
$stringFlag = !$stringFlag;
} else {
$result[$i] .= \sprintf(
'<span class="keyword">%s</span>',
\htmlspecialchars($token)
\htmlspecialchars($token, $this->htmlSpecialCharsFlags)
);
}
continue;
}
list($token, $value) = $token;
[$token, $value] = $token;
$value = \str_replace(
["\t", ' '],
['&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;'],
\htmlspecialchars($value, $this->htmlspecialcharsFlags)
\htmlspecialchars($value, $this->htmlSpecialCharsFlags)
);
if ($value === "\n") {

View File

@@ -7,6 +7,7 @@
<link href="{{path_to_root}}.css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}.css/nv.d3.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}.css/style.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}.css/custom.css" rel="stylesheet" type="text/css">
<!--[if lt IE 9]>
<script src="{{path_to_root}}.js/html5shiv.min.js"></script>
<script src="{{path_to_root}}.js/respond.min.js"></script>

View File

@@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="{{path_to_root}}.css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}.css/style.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}.css/custom.css" rel="stylesheet" type="text/css">
<!--[if lt IE 9]>
<script src="{{path_to_root}}.js/html5shiv.min.js"></script>
<script src="{{path_to_root}}.js/respond.min.js"></script>

View File

@@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="{{path_to_root}}.css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}.css/style.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}.css/custom.css" rel="stylesheet" type="text/css">
<!--[if lt IE 9]>
<script src="{{path_to_root}}.js/html5shiv.min.js"></script>
<script src="{{path_to_root}}.js/respond.min.js"></script>

View File

@@ -16,15 +16,17 @@ use SebastianBergmann\CodeCoverage\RuntimeException;
/**
* Uses var_export() to write a SebastianBergmann\CodeCoverage\CodeCoverage object to a file.
*/
class PHP
final class PHP
{
/**
* @param CodeCoverage $coverage
* @param string $target
* @param null|string $target
*
* @throws \SebastianBergmann\CodeCoverage\RuntimeException
*
* @return string
*/
public function process(CodeCoverage $coverage, $target = null)
public function process(CodeCoverage $coverage, ?string $target = null): string
{
$filter = $coverage->filter();

View File

@@ -19,29 +19,59 @@ use SebastianBergmann\CodeCoverage\Util;
*
* The output gets put into a text file our written to the CLI.
*/
class Text
final class Text
{
private $lowUpperBound;
private $highLowerBound;
private $showUncoveredFiles;
private $showOnlySummary;
private $colors = [
'green' => "\x1b[30;42m",
'yellow' => "\x1b[30;43m",
'red' => "\x1b[37;41m",
'header' => "\x1b[1;37;40m",
'reset' => "\x1b[0m",
'eol' => "\x1b[2K",
];
/**
* @var string
*/
private const COLOR_GREEN = "\x1b[30;42m";
/**
* @param int $lowUpperBound
* @param int $highLowerBound
* @param bool $showUncoveredFiles
* @param bool $showOnlySummary
* @var string
*/
public function __construct($lowUpperBound = 50, $highLowerBound = 90, $showUncoveredFiles = false, $showOnlySummary = false)
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;
@@ -49,17 +79,10 @@ class Text
$this->showOnlySummary = $showOnlySummary;
}
/**
* @param CodeCoverage $coverage
* @param bool $showColors
*
* @return string
*/
public function process(CodeCoverage $coverage, $showColors = false)
public function process(CodeCoverage $coverage, bool $showColors = false): string
{
$output = PHP_EOL . PHP_EOL;
$report = $coverage->getReport();
unset($coverage);
$colors = [
'header' => '',
@@ -75,17 +98,20 @@ class Text
$report->getNumTestedClassesAndTraits(),
$report->getNumClassesAndTraits()
);
$colors['methods'] = $this->getCoverageColor(
$report->getNumTestedMethods(),
$report->getNumMethods()
);
$colors['lines'] = $this->getCoverageColor(
$report->getNumExecutedLines(),
$report->getNumExecutableLines()
);
$colors['reset'] = $this->colors['reset'];
$colors['header'] = $this->colors['header'];
$colors['eol'] = $this->colors['eol'];
$colors['reset'] = self::COLOR_RESET;
$colors['header'] = self::COLOR_HEADER;
$colors['eol'] = self::COLOR_EOL;
}
$classes = \sprintf(
@@ -169,17 +195,18 @@ class Text
$classMethods++;
$classStatements += $method['executableLines'];
$coveredClassStatements += $method['executedLines'];
if ($method['coverage'] == 100) {
$coveredMethods++;
}
}
$namespace = '';
if (!empty($class['package']['namespace'])) {
$namespace = '\\' . $class['package']['namespace'] . '::';
} elseif (!empty($class['package']['fullPackage'])) {
$namespace = '@' . $class['package']['fullPackage'] . '::';
} else {
$namespace = '';
}
$classCoverage[$namespace . $className] = [
@@ -200,8 +227,7 @@ class Text
$resetColor = '';
foreach ($classCoverage as $fullQualifiedPath => $classInfo) {
if ($classInfo['statementsCovered'] != 0 ||
$this->showUncoveredFiles) {
if ($this->showUncoveredFiles || $classInfo['statementsCovered'] != 0) {
if ($showColors) {
$methodColor = $this->getCoverageColor($classInfo['methodsCovered'], $classInfo['methodCount']);
$linesColor = $this->getCoverageColor($classInfo['statementsCovered'], $classInfo['statementCount']);
@@ -218,7 +244,7 @@ class Text
return $output . PHP_EOL;
}
protected function getCoverageColor($numberOfCoveredElements, $totalNumberOfElements)
private function getCoverageColor(int $numberOfCoveredElements, int $totalNumberOfElements): string
{
$coverage = Util::percent(
$numberOfCoveredElements,
@@ -226,15 +252,17 @@ class Text
);
if ($coverage >= $this->highLowerBound) {
return $this->colors['green'];
} elseif ($coverage > $this->lowUpperBound) {
return $this->colors['yellow'];
return self::COLOR_GREEN;
}
return $this->colors['red'];
if ($coverage > $this->lowUpperBound) {
return self::COLOR_YELLOW;
}
return self::COLOR_RED;
}
protected function printCoverageCounts($numberOfCoveredElements, $totalNumberOfElements, $precision)
private function printCoverageCounts(int $numberOfCoveredElements, int $totalNumberOfElements, int $precision): string
{
$format = '%' . $precision . 's';
@@ -248,9 +276,9 @@ class Text
\sprintf($format, $totalNumberOfElements) . ')';
}
private function format($color, $padding, $string)
private function format($color, $padding, $string): string
{
$reset = $color ? $this->colors['reset'] : '';
$reset = $color ? self::COLOR_RESET : '';
return $color . \str_pad($string, $padding) . $reset . PHP_EOL;
}

View File

@@ -12,25 +12,19 @@ namespace SebastianBergmann\CodeCoverage\Report\Xml;
use SebastianBergmann\Environment\Runtime;
class BuildInformation
final class BuildInformation
{
/**
* @var \DOMElement
*/
private $contextNode;
/**
* @param \DOMElement $contextNode
*/
public function __construct(\DOMElement $contextNode)
{
$this->contextNode = $contextNode;
}
/**
* @param Runtime $runtime
*/
public function setRuntimeInformation(Runtime $runtime)
public function setRuntimeInformation(Runtime $runtime): void
{
$runtimeNode = $this->getNodeByName('runtime');
@@ -39,12 +33,6 @@ class BuildInformation
$runtimeNode->setAttribute('url', $runtime->getVendorUrl());
$driverNode = $this->getNodeByName('driver');
if ($runtime->isHHVM()) {
$driverNode->setAttribute('name', 'hhvm');
$driverNode->setAttribute('version', \constant('HHVM_VERSION'));
return;
}
if ($runtime->hasPHPDBGCodeCoverage()) {
$driverNode->setAttribute('name', 'phpdbg');
@@ -57,22 +45,28 @@ class BuildInformation
}
}
/**
* @param $name
*
* @return \DOMElement
*/
private function getNodeByName($name)
public function setBuildTime(\DateTime $date): void
{
$this->contextNode->setAttribute('time', $date->format('D M j G:i:s T Y'));
}
public function setGeneratorVersions(string $phpUnitVersion, string $coverageVersion): void
{
$this->contextNode->setAttribute('phpunit', $phpUnitVersion);
$this->contextNode->setAttribute('coverage', $coverageVersion);
}
private function getNodeByName(string $name): \DOMElement
{
$node = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
$name
)->item(0);
if (!$node) {
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
$name
)
);
@@ -80,22 +74,4 @@ class BuildInformation
return $node;
}
/**
* @param \DateTime $date
*/
public function setBuildTime(\DateTime $date)
{
$this->contextNode->setAttribute('time', $date->format('D M j G:i:s T Y'));
}
/**
* @param string $phpUnitVersion
* @param string $coverageVersion
*/
public function setGeneratorVersions($phpUnitVersion, $coverageVersion)
{
$this->contextNode->setAttribute('phpunit', $phpUnitVersion);
$this->contextNode->setAttribute('coverage', $coverageVersion);
}
}

View File

@@ -12,7 +12,7 @@ namespace SebastianBergmann\CodeCoverage\Report\Xml;
use SebastianBergmann\CodeCoverage\RuntimeException;
class Coverage
final class Coverage
{
/**
* @var \XMLWriter
@@ -29,17 +29,20 @@ class Coverage
*/
private $finalized = false;
public function __construct(\DOMElement $context, $line)
public function __construct(\DOMElement $context, string $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->startElementNS(null, $context->nodeName, 'https://schema.phpunit.de/coverage/1.0');
$this->writer->writeAttribute('nr', $line);
}
public function addTest($test)
/**
* @throws RuntimeException
*/
public function addTest(string $test): void
{
if ($this->finalized) {
throw new RuntimeException('Coverage Report already finalized');
@@ -50,7 +53,7 @@ class Coverage
$this->writer->endElement();
}
public function finalize()
public function finalize(): void
{
$this->writer->endElement();

View File

@@ -10,6 +10,6 @@
namespace SebastianBergmann\CodeCoverage\Report\Xml;
class Directory extends Node
final class Directory extends Node
{
}

View File

@@ -18,7 +18,7 @@ use SebastianBergmann\CodeCoverage\RuntimeException;
use SebastianBergmann\CodeCoverage\Version;
use SebastianBergmann\Environment\Runtime;
class Facade
final class Facade
{
/**
* @var string
@@ -35,23 +35,17 @@ class Facade
*/
private $phpUnitVersion;
/**
* @param string $version
*/
public function __construct($version)
public function __construct(string $version)
{
$this->phpUnitVersion = $version;
}
/**
* @param CodeCoverage $coverage
* @param string $target
*
* @throws RuntimeException
*/
public function process(CodeCoverage $coverage, $target)
public function process(CodeCoverage $coverage, string $target): void
{
if (\substr($target, -1, 1) != DIRECTORY_SEPARATOR) {
if (\substr($target, -1, 1) !== DIRECTORY_SEPARATOR) {
$target .= DIRECTORY_SEPARATOR;
}
@@ -71,7 +65,7 @@ class Facade
$this->saveDocument($this->project->asDom(), 'index');
}
private function setBuildInformation()
private function setBuildInformation(): void
{
$buildNode = $this->project->getBuildInformation();
$buildNode->setRuntimeInformation(new Runtime());
@@ -80,9 +74,9 @@ class Facade
}
/**
* @param string $directory
* @throws RuntimeException
*/
protected function initTargetDirectory($directory)
private function initTargetDirectory(string $directory): void
{
if (\file_exists($directory)) {
if (!\is_dir($directory)) {
@@ -96,33 +90,38 @@ class Facade
"'$directory' exists but is not writable."
);
}
} elseif (!@\mkdir($directory, 0777, true)) {
} elseif (!$this->createDirectory($directory)) {
throw new RuntimeException(
"'$directory' could not be created."
);
}
}
private function processDirectory(DirectoryNode $directory, Node $context)
private function processDirectory(DirectoryNode $directory, Node $context): void
{
$dirname = $directory->getName();
if ($this->project->getProjectSourceDirectory() === $dirname) {
$dirname = '/';
}
$dirObject = $context->addDirectory($dirname);
$directoryName = $directory->getName();
$this->setTotals($directory, $dirObject->getTotals());
if ($this->project->getProjectSourceDirectory() === $directoryName) {
$directoryName = '/';
}
$directoryObject = $context->addDirectory($directoryName);
$this->setTotals($directory, $directoryObject->getTotals());
foreach ($directory->getDirectories() as $node) {
$this->processDirectory($node, $dirObject);
$this->processDirectory($node, $directoryObject);
}
foreach ($directory->getFiles() as $node) {
$this->processFile($node, $dirObject);
$this->processFile($node, $directoryObject);
}
}
private function processFile(FileNode $file, Directory $context)
/**
* @throws RuntimeException
*/
private function processFile(FileNode $file, Directory $context): void
{
$fileObject = $context->addFile(
$file->getName(),
@@ -135,6 +134,7 @@ class Facade
$file->getPath(),
\strlen($this->project->getProjectSourceDirectory())
);
$fileReport = new Report($path);
$this->setTotals($file, $fileReport->getTotals());
@@ -168,7 +168,7 @@ class Facade
$this->saveDocument($fileReport->asDom(), $file->getId());
}
private function processUnit($unit, Report $report)
private function processUnit(array $unit, Report $report): void
{
if (isset($unit['className'])) {
$unitObject = $report->getClassObject($unit['className']);
@@ -206,7 +206,7 @@ class Facade
}
}
private function processFunction($function, Report $report)
private function processFunction(array $function, Report $report): void
{
$functionObject = $report->getFunctionObject($function['functionName']);
@@ -216,12 +216,12 @@ class Facade
$functionObject->setTotals($function['executableLines'], $function['executedLines'], $function['coverage']);
}
private function processTests(array $tests)
private function processTests(array $tests): void
{
$testsObject = $this->project->getTests();
foreach ($tests as $test => $result) {
if ($test == 'UNCOVERED_FILES_FROM_WHITELIST') {
if ($test === 'UNCOVERED_FILES_FROM_WHITELIST') {
continue;
}
@@ -229,7 +229,7 @@ class Facade
}
}
private function setTotals(AbstractNode $node, Totals $totals)
private function setTotals(AbstractNode $node, Totals $totals): void
{
$loc = $node->getLinesOfCode();
@@ -262,15 +262,15 @@ class Facade
);
}
/**
* @return string
*/
protected function getTargetDirectory()
private function getTargetDirectory(): string
{
return $this->target;
}
protected function saveDocument(\DOMDocument $document, $name)
/**
* @throws RuntimeException
*/
private function saveDocument(\DOMDocument $document, string $name): void
{
$filename = \sprintf('%s/%s.xml', $this->getTargetDirectory(), $name);
@@ -280,4 +280,9 @@ class Facade
$document->save($filename);
}
private function createDirectory(string $directory): bool
{
return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory));
}
}

View File

@@ -28,30 +28,14 @@ class File
$this->contextNode = $context;
}
/**
* @return \DOMElement
*/
protected function getContextNode()
{
return $this->contextNode;
}
/**
* @return \DOMDocument
*/
protected function getDomDocument()
{
return $this->dom;
}
public function getTotals()
public function getTotals(): Totals
{
$totalsContainer = $this->contextNode->firstChild;
if (!$totalsContainer) {
$totalsContainer = $this->contextNode->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'totals'
)
);
@@ -60,17 +44,17 @@ class File
return new Totals($totalsContainer);
}
public function getLineCoverage($line)
public function getLineCoverage(string $line): Coverage
{
$coverage = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'https://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',
'https://schema.phpunit.de/coverage/1.0',
'coverage'
)
);
@@ -78,11 +62,21 @@ class File
$lineNode = $coverage->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'line'
)
);
return new Coverage($lineNode, $line);
}
protected function getContextNode(): \DOMElement
{
return $this->contextNode;
}
protected function getDomDocument(): \DOMDocument
{
return $this->dom;
}
}

View File

@@ -10,31 +10,26 @@
namespace SebastianBergmann\CodeCoverage\Report\Xml;
class Method
final class Method
{
/**
* @var \DOMElement
*/
private $contextNode;
public function __construct(\DOMElement $context, $name)
public function __construct(\DOMElement $context, string $name)
{
$this->contextNode = $context;
$this->setName($name);
}
private function setName($name)
{
$this->contextNode->setAttribute('name', $name);
}
public function setSignature($signature)
public function setSignature(string $signature): void
{
$this->contextNode->setAttribute('signature', $signature);
}
public function setLines($start, $end = null)
public function setLines(string $start, ?string $end = null): void
{
$this->contextNode->setAttribute('start', $start);
@@ -43,15 +38,20 @@ class Method
}
}
public function setTotals($executable, $executed, $coverage)
public function setTotals(string $executable, string $executed, string $coverage): void
{
$this->contextNode->setAttribute('executable', $executable);
$this->contextNode->setAttribute('executed', $executed);
$this->contextNode->setAttribute('coverage', $coverage);
}
public function setCrap($crap)
public function setCrap(string $crap): void
{
$this->contextNode->setAttribute('crap', $crap);
}
private function setName(string $name): void
{
$this->contextNode->setAttribute('name', $name);
}
}

View File

@@ -10,7 +10,7 @@
namespace SebastianBergmann\CodeCoverage\Report\Xml;
class Node
abstract class Node
{
/**
* @var \DOMDocument
@@ -27,30 +27,19 @@ class Node
$this->setContextNode($context);
}
protected function setContextNode(\DOMElement $context)
{
$this->dom = $context->ownerDocument;
$this->contextNode = $context;
}
public function getDom()
public function getDom(): \DOMDocument
{
return $this->dom;
}
protected function getContextNode()
{
return $this->contextNode;
}
public function getTotals()
public function getTotals(): Totals
{
$totalsContainer = $this->getContextNode()->firstChild;
if (!$totalsContainer) {
$totalsContainer = $this->getContextNode()->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'totals'
)
);
@@ -59,10 +48,10 @@ class Node
return new Totals($totalsContainer);
}
public function addDirectory($name)
public function addDirectory(string $name): Directory
{
$dirNode = $this->getDom()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'directory'
);
@@ -72,10 +61,10 @@ class Node
return new Directory($dirNode);
}
public function addFile($name, $href)
public function addFile(string $name, string $href): File
{
$fileNode = $this->getDom()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'file'
);
@@ -85,4 +74,15 @@ class Node
return new File($fileNode);
}
protected function setContextNode(\DOMElement $context): void
{
$this->dom = $context->ownerDocument;
$this->contextNode = $context;
}
protected function getContextNode(): \DOMElement
{
return $this->contextNode;
}
}

View File

@@ -10,57 +10,30 @@
namespace SebastianBergmann\CodeCoverage\Report\Xml;
class Project extends Node
final class Project extends Node
{
/**
* @param string $directory
*/
public function __construct($directory)
public function __construct(string $directory)
{
$this->init();
$this->setProjectSourceDirectory($directory);
}
private function init()
{
$dom = new \DOMDocument();
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="http://schema.phpunit.de/coverage/1.0"><build/><project/></phpunit>');
$this->setContextNode(
$dom->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'project'
)->item(0)
);
}
private function setProjectSourceDirectory($name)
{
$this->getContextNode()->setAttribute('source', $name);
}
/**
* @return string
*/
public function getProjectSourceDirectory()
public function getProjectSourceDirectory(): string
{
return $this->getContextNode()->getAttribute('source');
}
/**
* @return BuildInformation
*/
public function getBuildInformation()
public function getBuildInformation(): BuildInformation
{
$buildNode = $this->getDom()->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'build'
)->item(0);
if (!$buildNode) {
$buildNode = $this->getDom()->documentElement->appendChild(
$this->getDom()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'build'
)
);
@@ -69,17 +42,17 @@ class Project extends Node
return new BuildInformation($buildNode);
}
public function getTests()
public function getTests(): Tests
{
$testsNode = $this->getContextNode()->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'https://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',
'https://schema.phpunit.de/coverage/1.0',
'tests'
)
);
@@ -88,8 +61,26 @@ class Project extends Node
return new Tests($testsNode);
}
public function asDom()
public function asDom(): \DOMDocument
{
return $this->getDom();
}
private function init(): void
{
$dom = new \DOMDocument;
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="https://schema.phpunit.de/coverage/1.0"><build/><project/></phpunit>');
$this->setContextNode(
$dom->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
'project'
)->item(0)
);
}
private function setProjectSourceDirectory(string $name): void
{
$this->getContextNode()->setAttribute('source', $name);
}
}

View File

@@ -10,38 +10,33 @@
namespace SebastianBergmann\CodeCoverage\Report\Xml;
class Report extends File
final class Report extends File
{
public function __construct($name)
public function __construct(string $name)
{
$dom = new \DOMDocument();
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="http://schema.phpunit.de/coverage/1.0"><file /></phpunit>');
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="https://schema.phpunit.de/coverage/1.0"><file /></phpunit>');
$contextNode = $dom->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'file'
)->item(0);
parent::__construct($contextNode);
$this->setName($name);
}
private function setName($name)
{
$this->getContextNode()->setAttribute('name', \basename($name));
$this->getContextNode()->setAttribute('path', \dirname($name));
}
public function asDom()
public function asDom(): \DOMDocument
{
return $this->getDomDocument();
}
public function getFunctionObject($name)
public function getFunctionObject($name): Method
{
$node = $this->getContextNode()->appendChild(
$this->getDomDocument()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'function'
)
);
@@ -49,39 +44,27 @@ class Report extends File
return new Method($node, $name);
}
public function getClassObject($name)
public function getClassObject($name): Unit
{
return $this->getUnitObject('class', $name);
}
public function getTraitObject($name)
public function getTraitObject($name): Unit
{
return $this->getUnitObject('trait', $name);
}
private function getUnitObject($tagName, $name)
{
$node = $this->getContextNode()->appendChild(
$this->getDomDocument()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
$tagName
)
);
return new Unit($node, $name);
}
public function getSource()
public function getSource(): Source
{
$source = $this->getContextNode()->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'source'
)->item(0);
if (!$source) {
$source = $this->getContextNode()->appendChild(
$this->getDomDocument()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'source'
)
);
@@ -89,4 +72,22 @@ class Report extends File
return new Source($source);
}
private function setName($name): void
{
$this->getContextNode()->setAttribute('name', \basename($name));
$this->getContextNode()->setAttribute('path', \dirname($name));
}
private function getUnitObject($tagName, $name): Unit
{
$node = $this->getContextNode()->appendChild(
$this->getDomDocument()->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
$tagName
)
);
return new Unit($node, $name);
}
}

View File

@@ -14,7 +14,7 @@ use TheSeer\Tokenizer\NamespaceUri;
use TheSeer\Tokenizer\Tokenizer;
use TheSeer\Tokenizer\XMLSerializer;
class Source
final class Source
{
/** @var \DOMElement */
private $context;
@@ -27,10 +27,7 @@ class Source
$this->context = $context;
}
/**
* @param string $source
*/
public function setSourceCode(string $source)
public function setSourceCode(string $source): void
{
$context = $this->context;

View File

@@ -10,18 +10,19 @@
namespace SebastianBergmann\CodeCoverage\Report\Xml;
class Tests
final 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
-1 => 'UNKNOWN', // PHPUnit_Runner_BaseTestRunner::STATUS_UNKNOWN
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)
@@ -29,11 +30,11 @@ class Tests
$this->contextNode = $context;
}
public function addTest($test, array $result)
public function addTest(string $test, array $result): void
{
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'test'
)
);

View File

@@ -12,7 +12,7 @@ namespace SebastianBergmann\CodeCoverage\Report\Xml;
use SebastianBergmann\CodeCoverage\Util;
class Totals
final class Totals
{
/**
* @var \DOMNode
@@ -50,27 +50,27 @@ class Totals
$dom = $container->ownerDocument;
$this->linesNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'lines'
);
$this->methodsNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'methods'
);
$this->functionsNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'functions'
);
$this->classesNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'classes'
);
$this->traitsNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'traits'
);
@@ -81,12 +81,12 @@ class Totals
$container->appendChild($this->traitsNode);
}
public function getContainer()
public function getContainer(): \DOMNode
{
return $this->container;
}
public function setNumLines($loc, $cloc, $ncloc, $executable, $executed)
public function setNumLines(int $loc, int $cloc, int $ncloc, int $executable, int $executed): void
{
$this->linesNode->setAttribute('total', $loc);
$this->linesNode->setAttribute('comments', $cloc);
@@ -95,47 +95,47 @@ class Totals
$this->linesNode->setAttribute('executed', $executed);
$this->linesNode->setAttribute(
'percent',
$executable === 0 ? 0 : \sprintf('%01.2F', Util::percent($executed, $executable, false))
$executable === 0 ? 0 : \sprintf('%01.2F', Util::percent($executed, $executable))
);
}
public function setNumClasses($count, $tested)
public function setNumClasses(int $count, int $tested): void
{
$this->classesNode->setAttribute('count', $count);
$this->classesNode->setAttribute('tested', $tested);
$this->classesNode->setAttribute(
'percent',
$count === 0 ? 0 : \sprintf('%01.2F', Util::percent($tested, $count, false))
$count === 0 ? 0 : \sprintf('%01.2F', Util::percent($tested, $count))
);
}
public function setNumTraits($count, $tested)
public function setNumTraits(int $count, int $tested): void
{
$this->traitsNode->setAttribute('count', $count);
$this->traitsNode->setAttribute('tested', $tested);
$this->traitsNode->setAttribute(
'percent',
$count === 0 ? 0 : \sprintf('%01.2F', Util::percent($tested, $count, false))
$count === 0 ? 0 : \sprintf('%01.2F', Util::percent($tested, $count))
);
}
public function setNumMethods($count, $tested)
public function setNumMethods(int $count, int $tested): void
{
$this->methodsNode->setAttribute('count', $count);
$this->methodsNode->setAttribute('tested', $tested);
$this->methodsNode->setAttribute(
'percent',
$count === 0 ? 0 : \sprintf('%01.2F', Util::percent($tested, $count, false))
$count === 0 ? 0 : \sprintf('%01.2F', Util::percent($tested, $count))
);
}
public function setNumFunctions($count, $tested)
public function setNumFunctions(int $count, int $tested): void
{
$this->functionsNode->setAttribute('count', $count);
$this->functionsNode->setAttribute('tested', $tested);
$this->functionsNode->setAttribute(
'percent',
$count === 0 ? 0 : \sprintf('%01.2F', Util::percent($tested, $count, false))
$count === 0 ? 0 : \sprintf('%01.2F', Util::percent($tested, $count))
);
}
}

View File

@@ -10,48 +10,43 @@
namespace SebastianBergmann\CodeCoverage\Report\Xml;
class Unit
final class Unit
{
/**
* @var \DOMElement
*/
private $contextNode;
public function __construct(\DOMElement $context, $name)
public function __construct(\DOMElement $context, string $name)
{
$this->contextNode = $context;
$this->setName($name);
}
private function setName($name)
{
$this->contextNode->setAttribute('name', $name);
}
public function setLines($start, $executable, $executed)
public function setLines(int $start, int $executable, int $executed): void
{
$this->contextNode->setAttribute('start', $start);
$this->contextNode->setAttribute('executable', $executable);
$this->contextNode->setAttribute('executed', $executed);
}
public function setCrap($crap)
public function setCrap(float $crap): void
{
$this->contextNode->setAttribute('crap', $crap);
}
public function setPackage($full, $package, $sub, $category)
public function setPackage(string $full, string $package, string $sub, string $category): void
{
$node = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'https://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',
'https://schema.phpunit.de/coverage/1.0',
'package'
)
);
@@ -63,17 +58,17 @@ class Unit
$node->setAttribute('category', $category);
}
public function setNamespace($namespace)
public function setNamespace(string $namespace): void
{
$node = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'https://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',
'https://schema.phpunit.de/coverage/1.0',
'namespace'
)
);
@@ -82,15 +77,20 @@ class Unit
$node->setAttribute('name', $namespace);
}
public function addMethod($name)
public function addMethod(string $name): Method
{
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'https://schema.phpunit.de/coverage/1.0',
'method'
)
);
return new Method($node, $name);
}
private function setName(string $name): void
{
$this->contextNode->setAttribute('name', $name);
}
}

View File

@@ -13,17 +13,12 @@ namespace SebastianBergmann\CodeCoverage;
/**
* Utility methods.
*/
class Util
final class Util
{
/**
* @param float $a
* @param float $b
* @param bool $asString
* @param bool $fixedWidth
*
* @return float|int|string
*/
public static function percent($a, $b, $asString = false, $fixedWidth = false)
public static function percent(float $a, float $b, bool $asString = false, bool $fixedWidth = false)
{
if ($asString && $b == 0) {
return '';

View File

@@ -12,17 +12,17 @@ namespace SebastianBergmann\CodeCoverage;
use SebastianBergmann\Version as VersionId;
class Version
final class Version
{
/**
* @var string
*/
private static $version;
/**
* @return string
*/
public static function id()
public static function id(): string
{
if (self::$version === null) {
$version = new VersionId('5.3.2', \dirname(__DIR__));
$version = new VersionId('6.0.7', \dirname(__DIR__));
self::$version = $version->getVersion();
}