/** * @param int $threshold */ public function __construct($threshold = 30) { if (!is_int($threshold)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(1, 'integer'); } $this->threshold = $threshold; }
/** * 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; } if (!$ignore) { $start = $token->getLine(); $end = $start + substr_count($token, "\n"); // Do not ignore the first line when there is a token // before the comment if (0 !== strpos($_token, $_line)) { $start++; } for ($i = $start; $i < $end; $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 (0 === strpos($_token, '/*') && '*/' === 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 // 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 boolean $flag * @throws PHP_CodeCoverage_Exception */ public function setProcessUncoveredFilesFromWhitelist($flag) { if (!is_bool($flag)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(1, 'boolean'); } $this->processUncoveredFilesFromWhitelist = $flag; }
/** * @param boolean $flag * @throws PHP_CodeCoverage_Exception */ public function setCacheTokens($flag) { if (!is_bool($flag)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(1, 'boolean'); } $this->cacheTokens = $flag; }
/** * Constructor. * * @param string $name * @param PHP_CodeCoverage_Report_Node $parent * @param array $coverageData * @param array $testData * @param boolean $cacheTokens * @throws PHP_CodeCoverage_Exception */ public function __construct($name, PHP_CodeCoverage_Report_Node $parent, array $coverageData, array $testData, $cacheTokens) { if (!is_bool($cacheTokens)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(1, 'boolean'); } parent::__construct($name, $parent); $this->coverageData = $coverageData; $this->testData = $testData; $this->ignoredLines = PHP_CodeCoverage_Util::getLinesToBeIgnored($this->getPath(), $cacheTokens); $this->cacheTokens = $cacheTokens; $this->calculateStatistics(); }
/** * @param bool $flag * @throws PHP_CodeCoverage_Exception */ public function setDisableIgnoredLines($flag) { if (!is_bool($flag)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(1, 'boolean'); } $this->disableIgnoredLines = $flag; }
/** * Returns the lines of a source file that should be ignored. * * @param string $filename * @param boolean $cacheTokens * @return array * @throws PHP_CodeCoverage_Exception */ public static function getLinesToBeIgnored($filename, $cacheTokens = TRUE) { if (!is_string($filename)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(1, 'string'); } if (!is_bool($cacheTokens)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(2, 'boolean'); } if (!isset(self::$ignoredLines[$filename])) { self::$ignoredLines[$filename] = array(); $ignore = FALSE; $stop = FALSE; $lines = file($filename); foreach ($lines as $index => $line) { if (!trim($line)) { self::$ignoredLines[$filename][$index + 1] = TRUE; } } if ($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': $count = substr_count($token, "\n"); $line = $token->getLine(); for ($i = $line; $i < $line + $count; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } if ($token instanceof PHP_Token_DOC_COMMENT) { // Workaround for the fact the DOC_COMMENT token // does not include the final \n character in its // text. if (substr(trim($lines[$i - 1]), -2) == '*/') { self::$ignoredLines[$filename][$i] = TRUE; } break; } $_token = trim($token); if ($_token == '// @codeCoverageIgnore' || $_token == '//@codeCoverageIgnore') { $ignore = TRUE; $stop = TRUE; } else { if ($_token == '// @codeCoverageIgnoreStart' || $_token == '//@codeCoverageIgnoreStart') { $ignore = TRUE; } else { if ($_token == '// @codeCoverageIgnoreEnd' || $_token == '//@codeCoverageIgnoreEnd') { $stop = TRUE; } } } break; case 'PHP_Token_INTERFACE': case 'PHP_Token_TRAIT': case 'PHP_Token_CLASS': case 'PHP_Token_FUNCTION': $docblock = $token->getDocblock(); if (strpos($docblock, '@codeCoverageIgnore')) { $endLine = $token->getEndLine(); for ($i = $token->getLine(); $i <= $endLine; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } } else { if ($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++) { self::$ignoredLines[$filename][$i] = TRUE; } } else { $firstMethod = array_shift($classes[$token->getName()]['methods']); $lastMethod = array_pop($classes[$token->getName()]['methods']); if ($lastMethod === NULL) { $lastMethod = $firstMethod; } for ($i = $token->getLine(); $i < $firstMethod['startLine']; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } for ($i = $token->getEndLine(); $i > $lastMethod['endLine']; $i--) { self::$ignoredLines[$filename][$i] = TRUE; } } } } break; case 'PHP_Token_INTERFACE': $endLine = $token->getEndLine(); for ($i = $token->getLine(); $i <= $endLine; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } break; case 'PHP_Token_NAMESPACE': self::$ignoredLines[$filename][$token->getEndLine()] = TRUE; // Intentional fallthrough // Intentional fallthrough case 'PHP_Token_OPEN_TAG': case 'PHP_Token_CLOSE_TAG': case 'PHP_Token_USE': self::$ignoredLines[$filename][$token->getLine()] = TRUE; break; } if ($ignore) { self::$ignoredLines[$filename][$token->getLine()] = TRUE; if ($stop) { $ignore = FALSE; $stop = FALSE; } } } } return self::$ignoredLines[$filename]; }