. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of Sebastian Bergmann nor the names of his * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @category Testing * @package PHPUnit * @author Sebastian Bergmann * @copyright 2002-2009 Sebastian Bergmann * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://www.phpunit.de/ * @since File available since Release 2.0.0 */ require_once 'PHPUnit/Util/FilterIterator.php'; /** * Utility class for code filtering. * * @category Testing * @package PHPUnit * @author Sebastian Bergmann * @copyright 2002-2009 Sebastian Bergmann * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @version Release: 3.3.17 * @link http://www.phpunit.de/ * @since Class available since Release 2.0.0 */ class PHPUnit_Util_Filter { /** * @var boolean */ public static $addUncoveredFilesFromWhitelist = TRUE; /** * @var boolean */ public static $filterPHPUnit = TRUE; /** * @var boolean */ protected static $filter = TRUE; /** * Source files that are blacklisted. * * @var array */ protected static $blacklistedFiles = array( 'DEFAULT' => array(), 'PHPUNIT' => array(), 'TESTS' => array() ); /** * Source files that are whitelisted. * * @var array */ protected static $whitelistedFiles = array(); /** * List of covered files. * * @var array */ protected static $coveredFiles = array(); /** * Adds a directory to the blacklist (recursively). * * @param string $directory * @param string $suffix * @param string $group * @throws RuntimeException * @since Method available since Release 3.1.5 */ public static function addDirectoryToFilter($directory, $suffix = '.php', $group = 'DEFAULT') { if (file_exists($directory)) { foreach (self::getIterator($directory, $suffix) as $file) { self::addFileToFilter($file->getPathName(), $group); } } else { throw new RuntimeException($directory . ' does not exist'); } } /** * Adds a new file to be filtered (blacklist). * * @param string $filename * @param string $group * @throws RuntimeException * @since Method available since Release 2.1.0 */ public static function addFileToFilter($filename, $group = 'DEFAULT') { if (file_exists($filename)) { $filename = realpath($filename); if (!isset(self::$blacklistedFiles[$group])) { self::$blacklistedFiles[$group] = array($filename); } else if (!in_array($filename, self::$blacklistedFiles[$group])) { self::$blacklistedFiles[$group][] = $filename; } } else { throw new RuntimeException($filename . ' does not exist'); } } /** * Removes a directory from the blacklist (recursively). * * @param string $directory * @param string $suffix * @param string $group * @throws RuntimeException * @since Method available since Release 3.1.5 */ public static function removeDirectoryFromFilter($directory, $suffix = '.php', $group = 'DEFAULT') { if (file_exists($directory)) { foreach (self::getIterator($directory, $suffix) as $file) { self::removeFileFromFilter($file->getPathName(), $group); } } else { throw new RuntimeException($directory . ' does not exist'); } } /** * Removes a file from the filter (blacklist). * * @param string $filename * @param string $group * @throws RuntimeException * @since Method available since Release 2.1.0 */ public static function removeFileFromFilter($filename, $group = 'DEFAULT') { if (file_exists($filename)) { if (isset(self::$blacklistedFiles[$group])) { $filename = realpath($filename); foreach (self::$blacklistedFiles[$group] as $key => $_filename) { if ($filename == $_filename) { unset(self::$blacklistedFiles[$group][$key]); } } } } else { throw new RuntimeException($filename . ' does not exist'); } } /** * Adds a directory to the whitelist (recursively). * * @param string $directory * @param string $suffix * @throws RuntimeException * @since Method available since Release 3.1.5 */ public static function addDirectoryToWhitelist($directory, $suffix = '.php') { if (file_exists($directory)) { foreach (self::getIterator($directory, $suffix) as $file) { self::addFileToWhitelist($file->getPathName()); } } else { throw new RuntimeException($directory . ' does not exist'); } } /** * Adds a new file to the whitelist. * * When the whitelist is empty (default), blacklisting is used. * When the whitelist is not empty, whitelisting is used. * * @param string $filename * @throws RuntimeException * @since Method available since Release 3.1.0 */ public static function addFileToWhitelist($filename) { if (file_exists($filename)) { $filename = realpath($filename); if (!in_array($filename, self::$whitelistedFiles)) { self::$whitelistedFiles[] = $filename; } } else { throw new RuntimeException($filename . ' does not exist'); } } /** * Removes a directory from the whitelist (recursively). * * @param string $directory * @param string $suffix * @throws RuntimeException * @since Method available since Release 3.1.5 */ public static function removeDirectoryFromWhitelist($directory, $suffix = '.php') { if (file_exists($directory)) { foreach (self::getIterator($directory, $suffix) as $file) { self::removeFileFromWhitelist($file->getPathName()); } } else { throw new RuntimeException($directory . ' does not exist'); } } /** * Removes a file from the whitelist. * * @param string $filename * @throws RuntimeException * @since Method available since Release 3.1.0 */ public static function removeFileFromWhitelist($filename) { if (file_exists($filename)) { $filename = realpath($filename); foreach (self::$whitelistedFiles as $key => $_filename) { if ($filename == $_filename) { unset(self::$whitelistedFiles[$key]); } } } else { throw new RuntimeException($filename . ' does not exist'); } } /** * Returns data about files within code coverage information, specifically * which ones will be filtered out and which ones may be whitelisted but not * touched by coverage. * * Returns a two-item array. The first item is an array indexed by filenames * with a boolean payload of whether they should be filtered out. * * The second item is an array of filenames which are * whitelisted but which are absent from the coverage information. * * @param array $codeCoverageInformation * @param boolean $filterTests * @return array */ public static function getFileCodeCoverageDisposition(array $codeCoverageInformation, $filterTests = TRUE) { if (!self::$filter) { return array(array(), array()); } $isFilteredCache = array(); $coveredFiles = array(); foreach ($codeCoverageInformation as $k => $test) { foreach (array_keys($test['executable']) as $file) { if (!isset($isFilteredCache[$file])) { $isFilteredCache[$file] = self::isFiltered( $file, $filterTests ); } } } $coveredFiles = array_keys($isFilteredCache); $missedFiles = array_diff(self::$whitelistedFiles, $coveredFiles); $missedFiles = array_filter($missedFiles, 'file_exists'); return array($isFilteredCache, $missedFiles); } /** * @param array $codeCoverageInformation * @param boolean $filterTests * @return array */ public static function getFilteredCodeCoverage(array $codeCoverageInformation, $filterTests = TRUE) { if (self::$filter) { list($isFilteredCache, $missedFiles) = self::getFileCodeCoverageDisposition( $codeCoverageInformation, $filterTests ); foreach ($codeCoverageInformation as $k => $test) { foreach (array_keys($test['files']) as $file) { if ($isFilteredCache[$file]) { unset($codeCoverageInformation[$k]['files'][$file]); } } foreach (array_keys($test['dead']) as $file) { if ($isFilteredCache[$file]) { unset($codeCoverageInformation[$k]['dead'][$file]); } } foreach (array_keys($test['executable']) as $file) { if ($isFilteredCache[$file]) { unset($codeCoverageInformation[$k]['executable'][$file]); } } } if (self::$addUncoveredFilesFromWhitelist) { foreach (self::$whitelistedFiles as $whitelistedFile) { if (!isset(self::$coveredFiles[$whitelistedFile])) { if (file_exists($whitelistedFile)) { xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); include_once $whitelistedFile; $coverage = xdebug_get_code_coverage(); xdebug_stop_code_coverage(); foreach ($coverage as $file => $fileCoverage) { if (!in_array($file, self::$whitelistedFiles) || isset(self::$coveredFiles[$file])) continue; foreach ($fileCoverage as $line => $flag) { if ($flag > 0) { $fileCoverage[$line] = -1; } } $codeCoverageInformation[] = array( 'test' => NULL, 'files' => array( $file => $fileCoverage ) ); self::addCoveredFile($file); } } } } } } return $codeCoverageInformation; } /** * Filters stack frames from PHPUnit classes. * * @param Exception $e * @param boolean $filterTests * @param boolean $asString * @return string */ public static function getFilteredStacktrace(Exception $e, $filterTests = TRUE, $asString = TRUE) { if ($asString === TRUE) { $filteredStacktrace = ''; } else { $filteredStacktrace = array(); } $eTrace = $e->getTrace(); if (!self::frameExists($eTrace, $e->getFile(), $e->getLine())) { array_unshift( $eTrace, array('file' => $e->getFile(), 'line' => $e->getLine()) ); } foreach ($eTrace as $frame) { if (!self::$filter || (isset($frame['file']) && !self::isFiltered($frame['file'], $filterTests, TRUE))) { if ($asString === TRUE) { $filteredStacktrace .= sprintf( "%s:%s\n", $frame['file'], isset($frame['line']) ? $frame['line'] : '?' ); } else { $filteredStacktrace[] = $frame; } } } return $filteredStacktrace; } /** * Activates or deactivates filtering. * * @param boolean $filter * @throws InvalidArgumentException * @since Method available since Release 3.0.0 */ public static function setFilter($filter) { if (is_bool($filter)) { self::$filter = $filter; } else { throw new InvalidArgumentException; } } /** * Returns a PHPUnit_Util_FilterIterator that iterates * over all files in the given directory that have the * given suffix. * * @param string $directory * @param string $suffix * @return Iterator * @since Method available since Release 3.1.5 */ protected static function getIterator($directory, $suffix) { return new PHPUnit_Util_FilterIterator( new RecursiveIteratorIterator( new RecursiveDirectoryIterator($directory) ), $suffix ); } /** * @param string $filename * @param boolean $filterTests * @param boolean $ignoreWhitelist * @return boolean * @since Method available since Release 2.1.3 */ public static function isFiltered($filename, $filterTests = TRUE, $ignoreWhitelist = FALSE) { $filename = realpath($filename); // Use blacklist. if ($ignoreWhitelist || empty(self::$whitelistedFiles)) { $blacklistedFiles = self::$blacklistedFiles['DEFAULT']; if ($filterTests) { $blacklistedFiles = array_merge( $blacklistedFiles, self::$blacklistedFiles['TESTS'] ); } if (self::$filterPHPUnit) { $blacklistedFiles = array_merge( $blacklistedFiles, self::$blacklistedFiles['PHPUNIT'] ); } if (in_array($filename, $blacklistedFiles)) { return TRUE; } foreach ($blacklistedFiles as $filteredFile) { if (strpos($filename, $filteredFile) !== FALSE) { return TRUE; } } return FALSE; } // Use whitelist. else { if (in_array($filename, self::$whitelistedFiles)) { return FALSE; } return TRUE; } } /** * Adds a file to the list of covered files. * * @param string $filename * @since Method available since Release 3.3.0 */ public static function addCoveredFile($filename) { self::$coveredFiles[$filename] = TRUE; } /** * Returns the list of covered files. * * @return array * @since Method available since Release 3.3.0 */ public static function getCoveredFiles() { return self::$coveredFiles; } /** * @param array $trace * @param string $file * @param int $line * @return boolean * @since Method available since Release 3.3.2 */ public static function frameExists(array $trace, $file, $line) { foreach ($trace as $frame) { if (isset($frame['file']) && $frame['file'] == $file && isset($frame['line']) && $frame['line'] == $line) { return TRUE; } } return FALSE; } } PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT'); ?>