Chris@14
|
1 <?php
|
Chris@14
|
2 /*
|
Chris@14
|
3 * This file is part of the php-code-coverage package.
|
Chris@14
|
4 *
|
Chris@14
|
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
|
Chris@14
|
6 *
|
Chris@14
|
7 * For the full copyright and license information, please view the LICENSE
|
Chris@14
|
8 * file that was distributed with this source code.
|
Chris@14
|
9 */
|
Chris@14
|
10
|
Chris@14
|
11 namespace SebastianBergmann\CodeCoverage\Driver;
|
Chris@14
|
12
|
Chris@14
|
13 use SebastianBergmann\CodeCoverage\RuntimeException;
|
Chris@14
|
14
|
Chris@14
|
15 /**
|
Chris@14
|
16 * Driver for PHPDBG's code coverage functionality.
|
Chris@14
|
17 *
|
Chris@14
|
18 * @codeCoverageIgnore
|
Chris@14
|
19 */
|
Chris@14
|
20 class PHPDBG implements Driver
|
Chris@14
|
21 {
|
Chris@14
|
22 /**
|
Chris@14
|
23 * Constructor.
|
Chris@14
|
24 */
|
Chris@14
|
25 public function __construct()
|
Chris@14
|
26 {
|
Chris@14
|
27 if (PHP_SAPI !== 'phpdbg') {
|
Chris@14
|
28 throw new RuntimeException(
|
Chris@14
|
29 'This driver requires the PHPDBG SAPI'
|
Chris@14
|
30 );
|
Chris@14
|
31 }
|
Chris@14
|
32
|
Chris@14
|
33 if (!\function_exists('phpdbg_start_oplog')) {
|
Chris@14
|
34 throw new RuntimeException(
|
Chris@14
|
35 'This build of PHPDBG does not support code coverage'
|
Chris@14
|
36 );
|
Chris@14
|
37 }
|
Chris@14
|
38 }
|
Chris@14
|
39
|
Chris@14
|
40 /**
|
Chris@14
|
41 * Start collection of code coverage information.
|
Chris@14
|
42 *
|
Chris@14
|
43 * @param bool $determineUnusedAndDead
|
Chris@14
|
44 */
|
Chris@14
|
45 public function start($determineUnusedAndDead = true)
|
Chris@14
|
46 {
|
Chris@14
|
47 phpdbg_start_oplog();
|
Chris@14
|
48 }
|
Chris@14
|
49
|
Chris@14
|
50 /**
|
Chris@14
|
51 * Stop collection of code coverage information.
|
Chris@14
|
52 *
|
Chris@14
|
53 * @return array
|
Chris@14
|
54 */
|
Chris@14
|
55 public function stop()
|
Chris@14
|
56 {
|
Chris@14
|
57 static $fetchedLines = [];
|
Chris@14
|
58
|
Chris@14
|
59 $dbgData = phpdbg_end_oplog();
|
Chris@14
|
60
|
Chris@14
|
61 if ($fetchedLines == []) {
|
Chris@14
|
62 $sourceLines = phpdbg_get_executable();
|
Chris@14
|
63 } else {
|
Chris@14
|
64 $newFiles = \array_diff(
|
Chris@14
|
65 \get_included_files(),
|
Chris@14
|
66 \array_keys($fetchedLines)
|
Chris@14
|
67 );
|
Chris@14
|
68
|
Chris@14
|
69 if ($newFiles) {
|
Chris@14
|
70 $sourceLines = phpdbg_get_executable(
|
Chris@14
|
71 ['files' => $newFiles]
|
Chris@14
|
72 );
|
Chris@14
|
73 } else {
|
Chris@14
|
74 $sourceLines = [];
|
Chris@14
|
75 }
|
Chris@14
|
76 }
|
Chris@14
|
77
|
Chris@14
|
78 foreach ($sourceLines as $file => $lines) {
|
Chris@14
|
79 foreach ($lines as $lineNo => $numExecuted) {
|
Chris@14
|
80 $sourceLines[$file][$lineNo] = self::LINE_NOT_EXECUTED;
|
Chris@14
|
81 }
|
Chris@14
|
82 }
|
Chris@14
|
83
|
Chris@14
|
84 $fetchedLines = \array_merge($fetchedLines, $sourceLines);
|
Chris@14
|
85
|
Chris@14
|
86 return $this->detectExecutedLines($fetchedLines, $dbgData);
|
Chris@14
|
87 }
|
Chris@14
|
88
|
Chris@14
|
89 /**
|
Chris@14
|
90 * Convert phpdbg based data into the format CodeCoverage expects
|
Chris@14
|
91 *
|
Chris@14
|
92 * @param array $sourceLines
|
Chris@14
|
93 * @param array $dbgData
|
Chris@14
|
94 *
|
Chris@14
|
95 * @return array
|
Chris@14
|
96 */
|
Chris@14
|
97 private function detectExecutedLines(array $sourceLines, array $dbgData)
|
Chris@14
|
98 {
|
Chris@14
|
99 foreach ($dbgData as $file => $coveredLines) {
|
Chris@14
|
100 foreach ($coveredLines as $lineNo => $numExecuted) {
|
Chris@14
|
101 // phpdbg also reports $lineNo=0 when e.g. exceptions get thrown.
|
Chris@14
|
102 // make sure we only mark lines executed which are actually executable.
|
Chris@14
|
103 if (isset($sourceLines[$file][$lineNo])) {
|
Chris@14
|
104 $sourceLines[$file][$lineNo] = self::LINE_EXECUTED;
|
Chris@14
|
105 }
|
Chris@14
|
106 }
|
Chris@14
|
107 }
|
Chris@14
|
108
|
Chris@14
|
109 return $sourceLines;
|
Chris@14
|
110 }
|
Chris@14
|
111 }
|