summaryrefslogtreecommitdiff
path: root/vendor/phpunit/php-code-coverage/src/Driver/PhpdbgDriver.php
blob: 7ee13b00fad3e52ac78e3bf0f9884f23a56ffe22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<?php declare(strict_types=1);
/*
 * This file is part of phpunit/php-code-coverage.
 *
 * (c) Sebastian Bergmann <[email protected]>
 *
 * 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 PHP_SAPI;
use const PHP_VERSION;
use function array_diff;
use function array_keys;
use function array_merge;
use function get_included_files;
use function phpdbg_end_oplog;
use function phpdbg_get_executable;
use function phpdbg_start_oplog;
use SebastianBergmann\CodeCoverage\RawCodeCoverageData;

/**
 * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
 */
final class PhpdbgDriver extends Driver
{
    /**
     * @throws PhpdbgNotAvailableException
     */
    public function __construct()
    {
        if (PHP_SAPI !== 'phpdbg') {
            throw new PhpdbgNotAvailableException;
        }
    }

    public function start(): void
    {
        phpdbg_start_oplog();
    }

    public function stop(): RawCodeCoverageData
    {
        static $fetchedLines = [];

        $dbgData = phpdbg_end_oplog();

        if ($fetchedLines === []) {
            $sourceLines = phpdbg_get_executable();
        } else {
            $newFiles = array_diff(get_included_files(), array_keys($fetchedLines));

            $sourceLines = [];

            if ($newFiles) {
                $sourceLines = phpdbg_get_executable(['files' => $newFiles]);
            }
        }

        foreach ($sourceLines as $file => $lines) {
            foreach ($lines as $lineNo => $numExecuted) {
                $sourceLines[$file][$lineNo] = self::LINE_NOT_EXECUTED;
            }
        }

        $fetchedLines = array_merge($fetchedLines, $sourceLines);

        return RawCodeCoverageData::fromXdebugWithoutPathCoverage(
            $this->detectExecutedLines($fetchedLines, $dbgData)
        );
    }

    public function nameAndVersion(): string
    {
        return 'PHPDBG ' . PHP_VERSION;
    }

    private function detectExecutedLines(array $sourceLines, array $dbgData): array
    {
        foreach ($dbgData as $file => $coveredLines) {
            foreach ($coveredLines as $lineNo => $numExecuted) {
                // phpdbg also reports $lineNo=0 when e.g. exceptions get thrown.
                // make sure we only mark lines executed which are actually executable.
                if (isset($sourceLines[$file][$lineNo])) {
                    $sourceLines[$file][$lineNo] = self::LINE_EXECUTED;
                }
            }
        }

        return $sourceLines;
    }
}