123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- <?php declare(strict_types=1);
- /*
- * This file is part of phpunit/php-code-coverage.
- *
- * (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;
- use const XDEBUG_CC_BRANCH_CHECK;
- use const XDEBUG_CC_DEAD_CODE;
- use const XDEBUG_CC_UNUSED;
- use const XDEBUG_FILTER_CODE_COVERAGE;
- use const XDEBUG_PATH_INCLUDE;
- use function explode;
- use function extension_loaded;
- use function getenv;
- use function in_array;
- use function ini_get;
- use function phpversion;
- use function version_compare;
- use function xdebug_get_code_coverage;
- use function xdebug_info;
- use function xdebug_set_filter;
- use function xdebug_start_code_coverage;
- use function xdebug_stop_code_coverage;
- use SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData;
- use SebastianBergmann\CodeCoverage\Filter;
- /**
- * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
- *
- * @see https://xdebug.org/docs/code_coverage#xdebug_get_code_coverage
- *
- * @psalm-type XdebugLinesCoverageType = array<int, int>
- * @psalm-type XdebugBranchCoverageType = array{
- * op_start: int,
- * op_end: int,
- * line_start: int,
- * line_end: int,
- * hit: int,
- * out: array<int, int>,
- * out_hit: array<int, int>,
- * }
- * @psalm-type XdebugPathCoverageType = array{
- * path: array<int, int>,
- * hit: int,
- * }
- * @psalm-type XdebugFunctionCoverageType = array{
- * branches: array<int, XdebugBranchCoverageType>,
- * paths: array<int, XdebugPathCoverageType>,
- * }
- * @psalm-type XdebugFunctionsCoverageType = array<string, XdebugFunctionCoverageType>
- * @psalm-type XdebugPathAndBranchesCoverageType = array{
- * lines: XdebugLinesCoverageType,
- * functions: XdebugFunctionsCoverageType,
- * }
- * @psalm-type XdebugCodeCoverageWithoutPathCoverageType = array<string, XdebugLinesCoverageType>
- * @psalm-type XdebugCodeCoverageWithPathCoverageType = array<string, XdebugPathAndBranchesCoverageType>
- */
- final class XdebugDriver extends Driver
- {
- /**
- * @throws XdebugNotAvailableException
- * @throws XdebugNotEnabledException
- */
- public function __construct(Filter $filter)
- {
- $this->ensureXdebugIsAvailable();
- $this->ensureXdebugCodeCoverageFeatureIsEnabled();
- if (!$filter->isEmpty()) {
- xdebug_set_filter(
- XDEBUG_FILTER_CODE_COVERAGE,
- XDEBUG_PATH_INCLUDE,
- $filter->files(),
- );
- }
- }
- public function canCollectBranchAndPathCoverage(): bool
- {
- return true;
- }
- public function canDetectDeadCode(): bool
- {
- return true;
- }
- public function start(): void
- {
- $flags = XDEBUG_CC_UNUSED;
- if ($this->detectsDeadCode() || $this->collectsBranchAndPathCoverage()) {
- $flags |= XDEBUG_CC_DEAD_CODE;
- }
- if ($this->collectsBranchAndPathCoverage()) {
- $flags |= XDEBUG_CC_BRANCH_CHECK;
- }
- xdebug_start_code_coverage($flags);
- }
- public function stop(): RawCodeCoverageData
- {
- $data = xdebug_get_code_coverage();
- xdebug_stop_code_coverage();
- if ($this->collectsBranchAndPathCoverage()) {
- /* @var XdebugCodeCoverageWithPathCoverageType $data */
- return RawCodeCoverageData::fromXdebugWithPathCoverage($data);
- }
- /* @var XdebugCodeCoverageWithoutPathCoverageType $data */
- return RawCodeCoverageData::fromXdebugWithoutPathCoverage($data);
- }
- public function nameAndVersion(): string
- {
- return 'Xdebug ' . phpversion('xdebug');
- }
- /**
- * @throws XdebugNotAvailableException
- */
- private function ensureXdebugIsAvailable(): void
- {
- if (!extension_loaded('xdebug')) {
- throw new XdebugNotAvailableException;
- }
- }
- /**
- * @throws XdebugNotEnabledException
- */
- private function ensureXdebugCodeCoverageFeatureIsEnabled(): void
- {
- if (version_compare(phpversion('xdebug'), '3.1', '>=')) {
- if (!in_array('coverage', xdebug_info('mode'), true)) {
- throw new XdebugNotEnabledException;
- }
- return;
- }
- $mode = getenv('XDEBUG_MODE');
- if ($mode === false || $mode === '') {
- $mode = ini_get('xdebug.mode');
- }
- if ($mode === false ||
- !in_array('coverage', explode(',', $mode), true)) {
- throw new XdebugNotEnabledException;
- }
- }
- }
|