gluon-web-remote

Web remote Administration for big size of gluon routers
git clone git://archive.git.mtrnord.blog/MTRNord/gluon-web-remote.git
Log | Files | Refs | README

CodeCoverage.php (26995B)


      1 <?php
      2 /*
      3  * This file is part of the PHP_CodeCoverage package.
      4  *
      5  * (c) Sebastian Bergmann <sebastian@phpunit.de>
      6  *
      7  * For the full copyright and license information, please view the LICENSE
      8  * file that was distributed with this source code.
      9  */
     10 
     11 use SebastianBergmann\Environment\Runtime;
     12 
     13 /**
     14  * Provides collection functionality for PHP code coverage information.
     15  *
     16  * @since Class available since Release 1.0.0
     17  */
     18 class PHP_CodeCoverage
     19 {
     20     /**
     21      * @var PHP_CodeCoverage_Driver
     22      */
     23     private $driver;
     24 
     25     /**
     26      * @var PHP_CodeCoverage_Filter
     27      */
     28     private $filter;
     29 
     30     /**
     31      * @var bool
     32      */
     33     private $cacheTokens = false;
     34 
     35     /**
     36      * @var bool
     37      */
     38     private $checkForUnintentionallyCoveredCode = false;
     39 
     40     /**
     41      * @var bool
     42      */
     43     private $forceCoversAnnotation = false;
     44 
     45     /**
     46      * @var bool
     47      */
     48     private $mapTestClassNameToCoveredClassName = false;
     49 
     50     /**
     51      * @var bool
     52      */
     53     private $addUncoveredFilesFromWhitelist = true;
     54 
     55     /**
     56      * @var bool
     57      */
     58     private $processUncoveredFilesFromWhitelist = false;
     59 
     60     /**
     61      * @var mixed
     62      */
     63     private $currentId;
     64 
     65     /**
     66      * Code coverage data.
     67      *
     68      * @var array
     69      */
     70     private $data = array();
     71 
     72     /**
     73      * @var array
     74      */
     75     private $ignoredLines = array();
     76 
     77     /**
     78      * @var bool
     79      */
     80     private $disableIgnoredLines = false;
     81 
     82     /**
     83      * Test data.
     84      *
     85      * @var array
     86      */
     87     private $tests = array();
     88 
     89     /**
     90      * Constructor.
     91      *
     92      * @param  PHP_CodeCoverage_Driver    $driver
     93      * @param  PHP_CodeCoverage_Filter    $filter
     94      * @throws PHP_CodeCoverage_Exception
     95      */
     96     public function __construct(PHP_CodeCoverage_Driver $driver = null, PHP_CodeCoverage_Filter $filter = null)
     97     {
     98         if ($driver === null) {
     99             $driver = $this->selectDriver();
    100         }
    101 
    102         if ($filter === null) {
    103             $filter = new PHP_CodeCoverage_Filter;
    104         }
    105 
    106         $this->driver = $driver;
    107         $this->filter = $filter;
    108     }
    109 
    110     /**
    111      * Returns the PHP_CodeCoverage_Report_Node_* object graph
    112      * for this PHP_CodeCoverage object.
    113      *
    114      * @return PHP_CodeCoverage_Report_Node_Directory
    115      * @since  Method available since Release 1.1.0
    116      */
    117     public function getReport()
    118     {
    119         $factory = new PHP_CodeCoverage_Report_Factory;
    120 
    121         return $factory->create($this);
    122     }
    123 
    124     /**
    125      * Clears collected code coverage data.
    126      */
    127     public function clear()
    128     {
    129         $this->currentId = null;
    130         $this->data      = array();
    131         $this->tests     = array();
    132     }
    133 
    134     /**
    135      * Returns the PHP_CodeCoverage_Filter used.
    136      *
    137      * @return PHP_CodeCoverage_Filter
    138      */
    139     public function filter()
    140     {
    141         return $this->filter;
    142     }
    143 
    144     /**
    145      * Returns the collected code coverage data.
    146      * Set $raw = true to bypass all filters.
    147      *
    148      * @param  bool  $raw
    149      * @return array
    150      * @since  Method available since Release 1.1.0
    151      */
    152     public function getData($raw = false)
    153     {
    154         if (!$raw && $this->addUncoveredFilesFromWhitelist) {
    155             $this->addUncoveredFilesFromWhitelist();
    156         }
    157 
    158         // We need to apply the blacklist filter a second time
    159         // when no whitelist is used.
    160         if (!$raw && !$this->filter->hasWhitelist()) {
    161             $this->applyListsFilter($this->data);
    162         }
    163 
    164         return $this->data;
    165     }
    166 
    167     /**
    168      * Sets the coverage data.
    169      *
    170      * @param array $data
    171      * @since Method available since Release 2.0.0
    172      */
    173     public function setData(array $data)
    174     {
    175         $this->data = $data;
    176     }
    177 
    178     /**
    179      * Returns the test data.
    180      *
    181      * @return array
    182      * @since  Method available since Release 1.1.0
    183      */
    184     public function getTests()
    185     {
    186         return $this->tests;
    187     }
    188 
    189     /**
    190      * Sets the test data.
    191      *
    192      * @param array $tests
    193      * @since Method available since Release 2.0.0
    194      */
    195     public function setTests(array $tests)
    196     {
    197         $this->tests = $tests;
    198     }
    199 
    200     /**
    201      * Start collection of code coverage information.
    202      *
    203      * @param  mixed                      $id
    204      * @param  bool                       $clear
    205      * @throws PHP_CodeCoverage_Exception
    206      */
    207     public function start($id, $clear = false)
    208     {
    209         if (!is_bool($clear)) {
    210             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    211                 1,
    212                 'boolean'
    213             );
    214         }
    215 
    216         if ($clear) {
    217             $this->clear();
    218         }
    219 
    220         $this->currentId = $id;
    221 
    222         $this->driver->start();
    223     }
    224 
    225     /**
    226      * Stop collection of code coverage information.
    227      *
    228      * @param  bool                       $append
    229      * @param  mixed                      $linesToBeCovered
    230      * @param  array                      $linesToBeUsed
    231      * @return array
    232      * @throws PHP_CodeCoverage_Exception
    233      */
    234     public function stop($append = true, $linesToBeCovered = array(), array $linesToBeUsed = array())
    235     {
    236         if (!is_bool($append)) {
    237             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    238                 1,
    239                 'boolean'
    240             );
    241         }
    242 
    243         if (!is_array($linesToBeCovered) && $linesToBeCovered !== false) {
    244             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    245                 2,
    246                 'array or false'
    247             );
    248         }
    249 
    250         $data = $this->driver->stop();
    251         $this->append($data, null, $append, $linesToBeCovered, $linesToBeUsed);
    252 
    253         $this->currentId = null;
    254 
    255         return $data;
    256     }
    257 
    258     /**
    259      * Appends code coverage data.
    260      *
    261      * @param  array                      $data
    262      * @param  mixed                      $id
    263      * @param  bool                       $append
    264      * @param  mixed                      $linesToBeCovered
    265      * @param  array                      $linesToBeUsed
    266      * @throws PHP_CodeCoverage_Exception
    267      */
    268     public function append(array $data, $id = null, $append = true, $linesToBeCovered = array(), array $linesToBeUsed = array())
    269     {
    270         if ($id === null) {
    271             $id = $this->currentId;
    272         }
    273 
    274         if ($id === null) {
    275             throw new PHP_CodeCoverage_Exception;
    276         }
    277 
    278         $this->applyListsFilter($data);
    279         $this->applyIgnoredLinesFilter($data);
    280         $this->initializeFilesThatAreSeenTheFirstTime($data);
    281 
    282         if (!$append) {
    283             return;
    284         }
    285 
    286         if ($id != 'UNCOVERED_FILES_FROM_WHITELIST') {
    287             $this->applyCoversAnnotationFilter(
    288                 $data,
    289                 $linesToBeCovered,
    290                 $linesToBeUsed
    291             );
    292         }
    293 
    294         if (empty($data)) {
    295             return;
    296         }
    297 
    298         $size   = 'unknown';
    299         $status = null;
    300 
    301         if ($id instanceof PHPUnit_Framework_TestCase) {
    302             $_size = $id->getSize();
    303 
    304             if ($_size == PHPUnit_Util_Test::SMALL) {
    305                 $size = 'small';
    306             } elseif ($_size == PHPUnit_Util_Test::MEDIUM) {
    307                 $size = 'medium';
    308             } elseif ($_size == PHPUnit_Util_Test::LARGE) {
    309                 $size = 'large';
    310             }
    311 
    312             $status = $id->getStatus();
    313             $id     = get_class($id) . '::' . $id->getName();
    314         } elseif ($id instanceof PHPUnit_Extensions_PhptTestCase) {
    315             $size = 'large';
    316             $id   = $id->getName();
    317         }
    318 
    319         $this->tests[$id] = array('size' => $size, 'status' => $status);
    320 
    321         foreach ($data as $file => $lines) {
    322             if (!$this->filter->isFile($file)) {
    323                 continue;
    324             }
    325 
    326             foreach ($lines as $k => $v) {
    327                 if ($v == PHP_CodeCoverage_Driver::LINE_EXECUTED) {
    328                     if (empty($this->data[$file][$k]) || !in_array($id, $this->data[$file][$k])) {
    329                         $this->data[$file][$k][] = $id;
    330                     }
    331                 }
    332             }
    333         }
    334     }
    335 
    336     /**
    337      * Merges the data from another instance of PHP_CodeCoverage.
    338      *
    339      * @param PHP_CodeCoverage $that
    340      */
    341     public function merge(PHP_CodeCoverage $that)
    342     {
    343         $this->filter->setBlacklistedFiles(
    344             array_merge($this->filter->getBlacklistedFiles(), $that->filter()->getBlacklistedFiles())
    345         );
    346 
    347         $this->filter->setWhitelistedFiles(
    348             array_merge($this->filter->getWhitelistedFiles(), $that->filter()->getWhitelistedFiles())
    349         );
    350 
    351         foreach ($that->data as $file => $lines) {
    352             if (!isset($this->data[$file])) {
    353                 if (!$this->filter->isFiltered($file)) {
    354                     $this->data[$file] = $lines;
    355                 }
    356 
    357                 continue;
    358             }
    359 
    360             foreach ($lines as $line => $data) {
    361                 if ($data !== null) {
    362                     if (!isset($this->data[$file][$line])) {
    363                         $this->data[$file][$line] = $data;
    364                     } else {
    365                         $this->data[$file][$line] = array_unique(
    366                             array_merge($this->data[$file][$line], $data)
    367                         );
    368                     }
    369                 }
    370             }
    371         }
    372 
    373         $this->tests = array_merge($this->tests, $that->getTests());
    374 
    375     }
    376 
    377     /**
    378      * @param  bool                       $flag
    379      * @throws PHP_CodeCoverage_Exception
    380      * @since  Method available since Release 1.1.0
    381      */
    382     public function setCacheTokens($flag)
    383     {
    384         if (!is_bool($flag)) {
    385             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    386                 1,
    387                 'boolean'
    388             );
    389         }
    390 
    391         $this->cacheTokens = $flag;
    392     }
    393 
    394     /**
    395      * @since Method available since Release 1.1.0
    396      */
    397     public function getCacheTokens()
    398     {
    399         return $this->cacheTokens;
    400     }
    401 
    402     /**
    403      * @param  bool                       $flag
    404      * @throws PHP_CodeCoverage_Exception
    405      * @since  Method available since Release 2.0.0
    406      */
    407     public function setCheckForUnintentionallyCoveredCode($flag)
    408     {
    409         if (!is_bool($flag)) {
    410             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    411                 1,
    412                 'boolean'
    413             );
    414         }
    415 
    416         $this->checkForUnintentionallyCoveredCode = $flag;
    417     }
    418 
    419     /**
    420      * @param  bool                       $flag
    421      * @throws PHP_CodeCoverage_Exception
    422      */
    423     public function setForceCoversAnnotation($flag)
    424     {
    425         if (!is_bool($flag)) {
    426             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    427                 1,
    428                 'boolean'
    429             );
    430         }
    431 
    432         $this->forceCoversAnnotation = $flag;
    433     }
    434 
    435     /**
    436      * @param  bool                       $flag
    437      * @throws PHP_CodeCoverage_Exception
    438      */
    439     public function setMapTestClassNameToCoveredClassName($flag)
    440     {
    441         if (!is_bool($flag)) {
    442             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    443                 1,
    444                 'boolean'
    445             );
    446         }
    447 
    448         $this->mapTestClassNameToCoveredClassName = $flag;
    449     }
    450 
    451     /**
    452      * @param  bool                       $flag
    453      * @throws PHP_CodeCoverage_Exception
    454      */
    455     public function setAddUncoveredFilesFromWhitelist($flag)
    456     {
    457         if (!is_bool($flag)) {
    458             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    459                 1,
    460                 'boolean'
    461             );
    462         }
    463 
    464         $this->addUncoveredFilesFromWhitelist = $flag;
    465     }
    466 
    467     /**
    468      * @param  bool                       $flag
    469      * @throws PHP_CodeCoverage_Exception
    470      */
    471     public function setProcessUncoveredFilesFromWhitelist($flag)
    472     {
    473         if (!is_bool($flag)) {
    474             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    475                 1,
    476                 'boolean'
    477             );
    478         }
    479 
    480         $this->processUncoveredFilesFromWhitelist = $flag;
    481     }
    482 
    483     /**
    484      * @param  bool                       $flag
    485      * @throws PHP_CodeCoverage_Exception
    486      */
    487     public function setDisableIgnoredLines($flag)
    488     {
    489         if (!is_bool($flag)) {
    490             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    491                 1,
    492                 'boolean'
    493             );
    494         }
    495 
    496         $this->disableIgnoredLines = $flag;
    497     }
    498 
    499     /**
    500      * Applies the @covers annotation filtering.
    501      *
    502      * @param  array                                                 $data
    503      * @param  mixed                                                 $linesToBeCovered
    504      * @param  array                                                 $linesToBeUsed
    505      * @throws PHP_CodeCoverage_Exception_UnintentionallyCoveredCode
    506      */
    507     private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, array $linesToBeUsed)
    508     {
    509         if ($linesToBeCovered === false ||
    510             ($this->forceCoversAnnotation && empty($linesToBeCovered))) {
    511             $data = array();
    512 
    513             return;
    514         }
    515 
    516         if (empty($linesToBeCovered)) {
    517             return;
    518         }
    519 
    520         if ($this->checkForUnintentionallyCoveredCode) {
    521             $this->performUnintentionallyCoveredCodeCheck(
    522                 $data,
    523                 $linesToBeCovered,
    524                 $linesToBeUsed
    525             );
    526         }
    527 
    528         $data = array_intersect_key($data, $linesToBeCovered);
    529 
    530         foreach (array_keys($data) as $filename) {
    531             $_linesToBeCovered = array_flip($linesToBeCovered[$filename]);
    532 
    533             $data[$filename] = array_intersect_key(
    534                 $data[$filename],
    535                 $_linesToBeCovered
    536             );
    537         }
    538     }
    539 
    540     /**
    541      * Applies the blacklist/whitelist filtering.
    542      *
    543      * @param array $data
    544      */
    545     private function applyListsFilter(array &$data)
    546     {
    547         foreach (array_keys($data) as $filename) {
    548             if ($this->filter->isFiltered($filename)) {
    549                 unset($data[$filename]);
    550             }
    551         }
    552     }
    553 
    554     /**
    555      * Applies the "ignored lines" filtering.
    556      *
    557      * @param array $data
    558      */
    559     private function applyIgnoredLinesFilter(array &$data)
    560     {
    561         foreach (array_keys($data) as $filename) {
    562             if (!$this->filter->isFile($filename)) {
    563                 continue;
    564             }
    565 
    566             foreach ($this->getLinesToBeIgnored($filename) as $line) {
    567                 unset($data[$filename][$line]);
    568             }
    569         }
    570     }
    571 
    572     /**
    573      * @param array $data
    574      * @since Method available since Release 1.1.0
    575      */
    576     private function initializeFilesThatAreSeenTheFirstTime(array $data)
    577     {
    578         foreach ($data as $file => $lines) {
    579             if ($this->filter->isFile($file) && !isset($this->data[$file])) {
    580                 $this->data[$file] = array();
    581 
    582                 foreach ($lines as $k => $v) {
    583                     $this->data[$file][$k] = $v == -2 ? null : array();
    584                 }
    585             }
    586         }
    587     }
    588 
    589     /**
    590      * Processes whitelisted files that are not covered.
    591      */
    592     private function addUncoveredFilesFromWhitelist()
    593     {
    594         $data           = array();
    595         $uncoveredFiles = array_diff(
    596             $this->filter->getWhitelist(),
    597             array_keys($this->data)
    598         );
    599 
    600         foreach ($uncoveredFiles as $uncoveredFile) {
    601             if (!file_exists($uncoveredFile)) {
    602                 continue;
    603             }
    604 
    605             if ($this->processUncoveredFilesFromWhitelist) {
    606                 $this->processUncoveredFileFromWhitelist(
    607                     $uncoveredFile,
    608                     $data,
    609                     $uncoveredFiles
    610                 );
    611             } else {
    612                 $data[$uncoveredFile] = array();
    613 
    614                 $lines = count(file($uncoveredFile));
    615 
    616                 for ($i = 1; $i <= $lines; $i++) {
    617                     $data[$uncoveredFile][$i] = PHP_CodeCoverage_Driver::LINE_NOT_EXECUTED;
    618                 }
    619             }
    620         }
    621 
    622         $this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
    623     }
    624 
    625     /**
    626      * @param string $uncoveredFile
    627      * @param array  $data
    628      * @param array  $uncoveredFiles
    629      */
    630     private function processUncoveredFileFromWhitelist($uncoveredFile, array &$data, array $uncoveredFiles)
    631     {
    632         $this->driver->start();
    633         include_once $uncoveredFile;
    634         $coverage = $this->driver->stop();
    635 
    636         foreach ($coverage as $file => $fileCoverage) {
    637             if (!isset($data[$file]) &&
    638                 in_array($file, $uncoveredFiles)) {
    639                 foreach (array_keys($fileCoverage) as $key) {
    640                     if ($fileCoverage[$key] == PHP_CodeCoverage_Driver::LINE_EXECUTED) {
    641                         $fileCoverage[$key] = PHP_CodeCoverage_Driver::LINE_NOT_EXECUTED;
    642                     }
    643                 }
    644 
    645                 $data[$file] = $fileCoverage;
    646             }
    647         }
    648     }
    649 
    650     /**
    651      * Returns the lines of a source file that should be ignored.
    652      *
    653      * @param  string                     $filename
    654      * @return array
    655      * @throws PHP_CodeCoverage_Exception
    656      * @since  Method available since Release 2.0.0
    657      */
    658     private function getLinesToBeIgnored($filename)
    659     {
    660         if (!is_string($filename)) {
    661             throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
    662                 1,
    663                 'string'
    664             );
    665         }
    666 
    667         if (!isset($this->ignoredLines[$filename])) {
    668             $this->ignoredLines[$filename] = array();
    669 
    670             if ($this->disableIgnoredLines) {
    671                 return $this->ignoredLines[$filename];
    672             }
    673 
    674             $ignore   = false;
    675             $stop     = false;
    676             $lines    = file($filename);
    677             $numLines = count($lines);
    678 
    679             foreach ($lines as $index => $line) {
    680                 if (!trim($line)) {
    681                     $this->ignoredLines[$filename][] = $index + 1;
    682                 }
    683             }
    684 
    685             if ($this->cacheTokens) {
    686                 $tokens = PHP_Token_Stream_CachingFactory::get($filename);
    687             } else {
    688                 $tokens = new PHP_Token_Stream($filename);
    689             }
    690 
    691             $classes = array_merge($tokens->getClasses(), $tokens->getTraits());
    692             $tokens  = $tokens->tokens();
    693 
    694             foreach ($tokens as $token) {
    695                 switch (get_class($token)) {
    696                     case 'PHP_Token_COMMENT':
    697                     case 'PHP_Token_DOC_COMMENT':
    698                         $_token = trim($token);
    699                         $_line  = trim($lines[$token->getLine() - 1]);
    700 
    701                         if ($_token == '// @codeCoverageIgnore' ||
    702                             $_token == '//@codeCoverageIgnore') {
    703                             $ignore = true;
    704                             $stop   = true;
    705                         } elseif ($_token == '// @codeCoverageIgnoreStart' ||
    706                             $_token == '//@codeCoverageIgnoreStart') {
    707                             $ignore = true;
    708                         } elseif ($_token == '// @codeCoverageIgnoreEnd' ||
    709                             $_token == '//@codeCoverageIgnoreEnd') {
    710                             $stop = true;
    711                         }
    712 
    713                         if (!$ignore) {
    714                             $start = $token->getLine();
    715                             $end   = $start + substr_count($token, "\n");
    716 
    717                             // Do not ignore the first line when there is a token
    718                             // before the comment
    719                             if (0 !== strpos($_token, $_line)) {
    720                                 $start++;
    721                             }
    722 
    723                             for ($i = $start; $i < $end; $i++) {
    724                                 $this->ignoredLines[$filename][] = $i;
    725                             }
    726 
    727                             // A DOC_COMMENT token or a COMMENT token starting with "/*"
    728                             // does not contain the final \n character in its text
    729                             if (isset($lines[$i-1]) && 0 === strpos($_token, '/*') && '*/' === substr(trim($lines[$i-1]), -2)) {
    730                                 $this->ignoredLines[$filename][] = $i;
    731                             }
    732                         }
    733                         break;
    734 
    735                     case 'PHP_Token_INTERFACE':
    736                     case 'PHP_Token_TRAIT':
    737                     case 'PHP_Token_CLASS':
    738                     case 'PHP_Token_FUNCTION':
    739                         $docblock = $token->getDocblock();
    740 
    741                         $this->ignoredLines[$filename][] = $token->getLine();
    742 
    743                         if (strpos($docblock, '@codeCoverageIgnore') || strpos($docblock, '@deprecated')) {
    744                             $endLine = $token->getEndLine();
    745 
    746                             for ($i = $token->getLine(); $i <= $endLine; $i++) {
    747                                 $this->ignoredLines[$filename][] = $i;
    748                             }
    749                         } elseif ($token instanceof PHP_Token_INTERFACE ||
    750                             $token instanceof PHP_Token_TRAIT ||
    751                             $token instanceof PHP_Token_CLASS) {
    752                             if (empty($classes[$token->getName()]['methods'])) {
    753                                 for ($i = $token->getLine();
    754                                      $i <= $token->getEndLine();
    755                                      $i++) {
    756                                     $this->ignoredLines[$filename][] = $i;
    757                                 }
    758                             } else {
    759                                 $firstMethod = array_shift(
    760                                     $classes[$token->getName()]['methods']
    761                                 );
    762 
    763                                 do {
    764                                     $lastMethod = array_pop(
    765                                         $classes[$token->getName()]['methods']
    766                                     );
    767                                 } while ($lastMethod !== null &&
    768                                     substr($lastMethod['signature'], 0, 18) == 'anonymous function');
    769 
    770                                 if ($lastMethod === null) {
    771                                     $lastMethod = $firstMethod;
    772                                 }
    773 
    774                                 for ($i = $token->getLine();
    775                                      $i < $firstMethod['startLine'];
    776                                      $i++) {
    777                                     $this->ignoredLines[$filename][] = $i;
    778                                 }
    779 
    780                                 for ($i = $token->getEndLine();
    781                                      $i > $lastMethod['endLine'];
    782                                      $i--) {
    783                                     $this->ignoredLines[$filename][] = $i;
    784                                 }
    785                             }
    786                         }
    787                         break;
    788 
    789                     case 'PHP_Token_NAMESPACE':
    790                         $this->ignoredLines[$filename][] = $token->getEndLine();
    791 
    792                     // Intentional fallthrough
    793                     case 'PHP_Token_OPEN_TAG':
    794                     case 'PHP_Token_CLOSE_TAG':
    795                     case 'PHP_Token_USE':
    796                         $this->ignoredLines[$filename][] = $token->getLine();
    797                         break;
    798                 }
    799 
    800                 if ($ignore) {
    801                     $this->ignoredLines[$filename][] = $token->getLine();
    802 
    803                     if ($stop) {
    804                         $ignore = false;
    805                         $stop   = false;
    806                     }
    807                 }
    808             }
    809 
    810             $this->ignoredLines[$filename][] = $numLines + 1;
    811 
    812             $this->ignoredLines[$filename] = array_unique(
    813                 $this->ignoredLines[$filename]
    814             );
    815 
    816             sort($this->ignoredLines[$filename]);
    817         }
    818 
    819         return $this->ignoredLines[$filename];
    820     }
    821 
    822     /**
    823      * @param  array                                                 $data
    824      * @param  array                                                 $linesToBeCovered
    825      * @param  array                                                 $linesToBeUsed
    826      * @throws PHP_CodeCoverage_Exception_UnintentionallyCoveredCode
    827      * @since Method available since Release 2.0.0
    828      */
    829     private function performUnintentionallyCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed)
    830     {
    831         $allowedLines = $this->getAllowedLines(
    832             $linesToBeCovered,
    833             $linesToBeUsed
    834         );
    835 
    836         $message = '';
    837 
    838         foreach ($data as $file => $_data) {
    839             foreach ($_data as $line => $flag) {
    840                 if ($flag == 1 &&
    841                     (!isset($allowedLines[$file]) ||
    842                         !isset($allowedLines[$file][$line]))) {
    843                     $message .= sprintf(
    844                         '- %s:%d' . PHP_EOL,
    845                         $file,
    846                         $line
    847                     );
    848                 }
    849             }
    850         }
    851 
    852         if (!empty($message)) {
    853             throw new PHP_CodeCoverage_Exception_UnintentionallyCoveredCode(
    854                 $message
    855             );
    856         }
    857     }
    858 
    859     /**
    860      * @param  array $linesToBeCovered
    861      * @param  array $linesToBeUsed
    862      * @return array
    863      * @since Method available since Release 2.0.0
    864      */
    865     private function getAllowedLines(array $linesToBeCovered, array $linesToBeUsed)
    866     {
    867         $allowedLines = array();
    868 
    869         foreach (array_keys($linesToBeCovered) as $file) {
    870             if (!isset($allowedLines[$file])) {
    871                 $allowedLines[$file] = array();
    872             }
    873 
    874             $allowedLines[$file] = array_merge(
    875                 $allowedLines[$file],
    876                 $linesToBeCovered[$file]
    877             );
    878         }
    879 
    880         foreach (array_keys($linesToBeUsed) as $file) {
    881             if (!isset($allowedLines[$file])) {
    882                 $allowedLines[$file] = array();
    883             }
    884 
    885             $allowedLines[$file] = array_merge(
    886                 $allowedLines[$file],
    887                 $linesToBeUsed[$file]
    888             );
    889         }
    890 
    891         foreach (array_keys($allowedLines) as $file) {
    892             $allowedLines[$file] = array_flip(
    893                 array_unique($allowedLines[$file])
    894             );
    895         }
    896 
    897         return $allowedLines;
    898     }
    899 
    900     /**
    901      * @return PHP_CodeCoverage_Driver
    902      * @throws PHP_CodeCoverage_Exception
    903      */
    904     private function selectDriver()
    905     {
    906         $runtime = new Runtime;
    907 
    908         if (!$runtime->canCollectCodeCoverage()) {
    909             throw new PHP_CodeCoverage_Exception('No code coverage driver available');
    910         }
    911 
    912         if ($runtime->isHHVM()) {
    913             return new PHP_CodeCoverage_Driver_HHVM;
    914         } elseif ($runtime->isPHPDBG()) {
    915             return new PHP_CodeCoverage_Driver_PHPDBG;
    916         } else {
    917             return new PHP_CodeCoverage_Driver_Xdebug;
    918         }
    919     }
    920 }