Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c3d2cd5
Merge branch '2.0'
sebastianbergmann Feb 24, 2014
1bd972a
Merge branch '2.0'
sebastianbergmann Feb 24, 2014
2642382
Merge branch '2.0'
sebastianbergmann Mar 2, 2014
1532eca
Fix dependency
sebastianbergmann Mar 2, 2014
4da8aac
Merge branch '2.0'
sebastianbergmann Mar 4, 2014
06d5e5e
Merge branch '2.0'
sebastianbergmann Mar 4, 2014
c773f6a
Merge branch '2.0'
whatthejeff Mar 5, 2014
86cb041
Eliminate unused local variable
sebastianbergmann Mar 16, 2014
1068cf7
Eliminate unused local variable
sebastianbergmann Mar 16, 2014
4876f10
Add/Fix docblocks
sebastianbergmann Mar 16, 2014
edd13bb
Blacklist SebastianBergmann\Comparator\Comparator
sebastianbergmann Mar 17, 2014
258c601
Merge branch '2.0'
sebastianbergmann Mar 17, 2014
f1478a8
Merge branch '2.0'
sebastianbergmann Mar 19, 2014
de3b3dd
Move list of blacklisted classes to PHPUnit
sebastianbergmann Mar 19, 2014
f751861
Refactoring of data filtering and data cleanup
sebastianbergmann Mar 20, 2014
a5cf7ee
fixed Report\Node to handle root directory
julianseeger Mar 4, 2014
d83d41d
removed unneccessary todos
julianseeger Mar 4, 2014
ed2da23
fixed Factory to support "/" as the only common path
julianseeger Mar 4, 2014
6ab6543
refactoring of support for "/" as the only common path
julianseeger Mar 4, 2014
3aedd79
NodeTest: replaced DefaultNode class by a dynamic stub
julianseeger Mar 4, 2014
1b86a83
Make tests pass on HHVM
sebastianbergmann Mar 21, 2014
adacb53
Add missing call to ensureDriverCanWork() in constructor
sebastianbergmann Mar 25, 2014
2c17b8d
Bump version
sebastianbergmann Mar 25, 2014
d19de35
Merge branch '2.0'
sebastianbergmann Mar 28, 2014
818ec8b
Merge branch '2.0'
sebastianbergmann Apr 3, 2014
0f87633
Target PHPUnit 4.2
sebastianbergmann Apr 6, 2014
8cdc401
Document dependency on ext/xmlwriter
sebastianbergmann Apr 26, 2014
2481186
Merge branch '2.0'
sebastianbergmann Apr 27, 2014
71eedb7
Merge pull request #224 from julianseeger/master
sebastianbergmann Apr 27, 2014
f0565e2
Merge branch '2.0'
sebastianbergmann Apr 27, 2014
34b9a42
Eliminate dead code
sebastianbergmann Apr 30, 2014
8d0fee3
Fix link from dashboard view to directory view
sebastianbergmann Apr 30, 2014
a995604
Merge branch '2.0'
sebastianbergmann Apr 30, 2014
2c00856
code coverage driver hhvm fix
May 14, 2014
658a716
code coverage driver hhvm fix
May 14, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,17 @@
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"irc": "irc://irc.freenode.net/phpunit"
},
"minimum-stability": "dev",
"require": {
"php": ">=5.3.3",
"phpunit/php-file-iterator": "~1.3.1",
"phpunit/php-token-stream": "~1.2.2",
"phpunit/php-text-template": "~1.2",
"sebastian/environment": "~1.0",
"sebastian/version": "~1.0.3"
"phpunit/php-file-iterator": ">=1.3.0",
"phpunit/php-token-stream": ">=1.1.3",
"phpunit/php-text-template": ">=1.2.0",
"sebastian/environment": ">=1.0.0",
"sebastian/version": ">=1.0.0"
},
"require-dev": {
"phpunit/phpunit": ">=4.0.0,<4.1.0",
"phpunit/phpunit": "4.2.*@dev",
"ext-xdebug": ">=2.1.4"
},
"suggest": {
Expand All @@ -44,11 +45,10 @@
},
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
"dev-master": "3.0.x-dev"
}
},
"include-path": [
""
]
}

279 changes: 17 additions & 262 deletions src/CodeCoverage.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ class PHP_CodeCoverage
*/
private $filter;

/**
* @var PHP_CodeCoverage_Parser
*/
private $parser;

/**
* @var boolean
*/
Expand Down Expand Up @@ -110,11 +115,6 @@ class PHP_CodeCoverage
*/
private $data = array();

/**
* @var array
*/
private $ignoredLines = array();

/**
* Test data.
*
Expand All @@ -131,24 +131,27 @@ class PHP_CodeCoverage
*/
public function __construct(PHP_CodeCoverage_Driver $driver = null, PHP_CodeCoverage_Filter $filter = null)
{
if ($filter === null) {
$filter = new PHP_CodeCoverage_Filter;
}

$parser = new PHP_CodeCoverage_Parser;

if ($driver === null) {
$runtime = new Runtime;

if ($runtime->isHHVM()) {
$driver = new PHP_CodeCoverage_Driver_HHVM;
$driver = new PHP_CodeCoverage_Driver_HHVM($filter, $parser);
} elseif ($runtime->hasXdebug()) {
$driver = new PHP_CodeCoverage_Driver_Xdebug;
$driver = new PHP_CodeCoverage_Driver_Xdebug($filter, $parser);
} else {
throw new PHP_CodeCoverage_Exception('No code coverage driver available');
}
}

if ($filter === null) {
$filter = new PHP_CodeCoverage_Filter;
}

$this->driver = $driver;
$this->filter = $filter;
$this->parser = $parser;
}

/**
Expand Down Expand Up @@ -199,12 +202,6 @@ public function getData($raw = false)
$this->addUncoveredFilesFromWhitelist();
}

// We need to apply the blacklist filter a second time
// when no whitelist is used.
if (!$raw && !$this->filter->hasWhitelist()) {
$this->applyListsFilter($this->data);
}

return $this->data;
}

Expand Down Expand Up @@ -319,8 +316,6 @@ public function append(array $data, $id = null, $append = true, $linesToBeCovere
throw new PHP_CodeCoverage_Exception;
}

$this->applyListsFilter($data);
$this->applyIgnoredLinesFilter($data);
$this->initializeFilesThatAreSeenTheFirstTime($data);

if (!$append) {
Expand Down Expand Up @@ -409,6 +404,8 @@ public function setCacheTokens($flag)
);
}

$this->parser->setCacheTokens($flag);

$this->cacheTokens = $flag;
}

Expand Down Expand Up @@ -542,42 +539,6 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
}
}

/**
* Applies the blacklist/whitelist filtering.
*
* @param array $data
*/
private function applyListsFilter(array &$data)
{
foreach (array_keys($data) as $filename) {
if ($this->filter->isFiltered($filename)) {
unset($data[$filename]);
}
}
}

/**
* Applies the "ignored lines" filtering.
*
* @param array $data
*/
private function applyIgnoredLinesFilter(array &$data)
{
foreach (array_keys($data) as $filename) {
if (!$this->filter->isFile($filename)) {
continue;
}

foreach ($this->getLinesToBeIgnored($filename) as $line) {
unset($data[$filename][$line]);
}

if (empty($data[$filename])) {
unset($data[$filename]);
}
}
}

/**
* @param array $data
* @since Method available since Release 1.1.0
Expand Down Expand Up @@ -656,171 +617,6 @@ private function processUncoveredFileFromWhitelist($uncoveredFile, array &$data,
}
}

/**
* Returns the lines of a source file that should be ignored.
*
* @param string $filename
* @return array
* @throws PHP_CodeCoverage_Exception
* @since Method available since Release 2.0.0
*/
private function getLinesToBeIgnored($filename)
{
if (!is_string($filename)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'string'
);
}

if (!isset($this->ignoredLines[$filename])) {
$this->ignoredLines[$filename] = array();
$ignore = false;
$stop = false;
$lines = file($filename);
$numLines = count($lines);

foreach ($lines as $index => $line) {
if (!trim($line)) {
$this->ignoredLines[$filename][] = $index + 1;
}
}

if ($this->cacheTokens) {
$tokens = PHP_Token_Stream_CachingFactory::get($filename);
} else {
$tokens = new PHP_Token_Stream($filename);
}

$classes = array_merge($tokens->getClasses(), $tokens->getTraits());
$tokens = $tokens->tokens();

foreach ($tokens as $token) {
switch (get_class($token)) {
case 'PHP_Token_COMMENT':
case 'PHP_Token_DOC_COMMENT':
$_token = trim($token);
$_line = trim($lines[$token->getLine() - 1]);

if ($_token == '// @codeCoverageIgnore' ||
$_token == '//@codeCoverageIgnore') {
$ignore = true;
$stop = true;
} elseif ($_token == '// @codeCoverageIgnoreStart' ||
$_token == '//@codeCoverageIgnoreStart') {
$ignore = true;
} elseif ($_token == '// @codeCoverageIgnoreEnd' ||
$_token == '//@codeCoverageIgnoreEnd') {
$stop = true;
}

// Do not ignore the whole line when there is a token
// before the comment on the same line
if (0 === strpos($_token, $_line)) {
$count = substr_count($token, "\n");
$line = $token->getLine();

for ($i = $line; $i < $line + $count; $i++) {
$this->ignoredLines[$filename][] = $i;
}

if ($token instanceof PHP_Token_DOC_COMMENT) {
// The DOC_COMMENT token does not contain the
// final \n character in its text
if (substr(trim($lines[$i-1]), -2) == '*/') {
$this->ignoredLines[$filename][] = $i;
}
}
}
break;

case 'PHP_Token_INTERFACE':
case 'PHP_Token_TRAIT':
case 'PHP_Token_CLASS':
case 'PHP_Token_FUNCTION':
$docblock = $token->getDocblock();

$this->ignoredLines[$filename][] = $token->getLine();

if (strpos($docblock, '@codeCoverageIgnore')) {
$endLine = $token->getEndLine();

for ($i = $token->getLine(); $i <= $endLine; $i++) {
$this->ignoredLines[$filename][] = $i;
}
} elseif ($token instanceof PHP_Token_INTERFACE ||
$token instanceof PHP_Token_TRAIT ||
$token instanceof PHP_Token_CLASS) {
if (empty($classes[$token->getName()]['methods'])) {
for ($i = $token->getLine();
$i <= $token->getEndLine();
$i++) {
$this->ignoredLines[$filename][] = $i;
}
} else {
$firstMethod = array_shift(
$classes[$token->getName()]['methods']
);

do {
$lastMethod = array_pop(
$classes[$token->getName()]['methods']
);
} while ($lastMethod !== null &&
substr($lastMethod['signature'], 0, 18) == 'anonymous function');

if ($lastMethod === null) {
$lastMethod = $firstMethod;
}

for ($i = $token->getLine();
$i < $firstMethod['startLine'];
$i++) {
$this->ignoredLines[$filename][] = $i;
}

for ($i = $token->getEndLine();
$i > $lastMethod['endLine'];
$i--) {
$this->ignoredLines[$filename][] = $i;
}
}
}
break;

case 'PHP_Token_NAMESPACE':
$this->ignoredLines[$filename][] = $token->getEndLine();

// Intentional fallthrough
case 'PHP_Token_OPEN_TAG':
case 'PHP_Token_CLOSE_TAG':
case 'PHP_Token_USE':
$this->ignoredLines[$filename][] = $token->getLine();
break;
}

if ($ignore) {
$this->ignoredLines[$filename][] = $token->getLine();

if ($stop) {
$ignore = false;
$stop = false;
}
}
}

$this->ignoredLines[$filename][] = $numLines + 1;

$this->ignoredLines[$filename] = array_unique(
$this->ignoredLines[$filename]
);

sort($this->ignoredLines[$filename]);
}

return $this->ignoredLines[$filename];
}

/**
* @param array $data
* @param array $linesToBeCovered
Expand All @@ -830,7 +626,7 @@ private function getLinesToBeIgnored($filename)
*/
private function performUnintentionallyCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed)
{
$allowedLines = $this->getAllowedLines(
$allowedLines = $this->parser->getAllowedLines(
$linesToBeCovered,
$linesToBeUsed
);
Expand All @@ -857,45 +653,4 @@ private function performUnintentionallyCoveredCodeCheck(array &$data, array $lin
);
}
}

/**
* @param array $linesToBeCovered
* @param array $linesToBeUsed
* @return array
* @since Method available since Release 2.0.0
*/
private function getAllowedLines(array $linesToBeCovered, array $linesToBeUsed)
{
$allowedLines = array();

foreach (array_keys($linesToBeCovered) as $file) {
if (!isset($allowedLines[$file])) {
$allowedLines[$file] = array();
}

$allowedLines[$file] = array_merge(
$allowedLines[$file],
$linesToBeCovered[$file]
);
}

foreach (array_keys($linesToBeUsed) as $file) {
if (!isset($allowedLines[$file])) {
$allowedLines[$file] = array();
}

$allowedLines[$file] = array_merge(
$allowedLines[$file],
$linesToBeUsed[$file]
);
}

foreach (array_keys($allowedLines) as $file) {
$allowedLines[$file] = array_flip(
array_unique($allowedLines[$file])
);
}

return $allowedLines;
}
}
Loading