1 | <?php |
||
18 | class RemoteCoverageTool |
||
19 | { |
||
20 | |||
21 | const TEST_ID_VARIABLE = 'PHPUNIT_MINK_TEST_ID'; |
||
22 | |||
23 | const DATA_DIRECTORY_VARIABLE = 'PHPUNIT_MINK_COVERAGE_DATA_DIRECTORY'; |
||
24 | |||
25 | /** |
||
26 | * Directory for coverage information collection. |
||
27 | * |
||
28 | * @var string |
||
29 | */ |
||
30 | protected $dataDirectory; |
||
31 | |||
32 | /** |
||
33 | * Files, excluded from coverage collection. |
||
34 | * |
||
35 | * @var array |
||
36 | */ |
||
37 | protected $excludedFiles = array(__FILE__); |
||
38 | |||
39 | /** |
||
40 | * Collects & reports coverage information. |
||
41 | * |
||
42 | * @param string|null $data_directory Directory for coverage information collection. |
||
43 | * |
||
44 | * @return void |
||
45 | */ |
||
46 | public static function init($data_directory = null) |
||
47 | { |
||
48 | $coverage_tool = new self($data_directory); |
||
49 | $mode = isset($_GET['rct_mode']) ? $_GET['rct_mode'] : ''; |
||
50 | |||
51 | if ( $mode == 'output' ) { |
||
52 | echo $coverage_tool->aggregateCoverageInformation(); |
||
53 | } |
||
54 | else { |
||
55 | $coverage_tool->startCollection(); |
||
56 | register_shutdown_function(array($coverage_tool, 'stopCollection')); |
||
57 | } |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Creates an instance of remove coverage tool. |
||
62 | * |
||
63 | * @param string|null $data_directory Directory for coverage information collection. |
||
64 | */ |
||
65 | public function __construct($data_directory = null) |
||
66 | { |
||
67 | if ( !isset($data_directory) ) { |
||
68 | if ( isset($GLOBALS[self::DATA_DIRECTORY_VARIABLE]) ) { |
||
69 | $this->dataDirectory = $this->assertDirectory($GLOBALS[self::DATA_DIRECTORY_VARIABLE]); |
||
70 | } |
||
71 | else { |
||
72 | $this->dataDirectory = getcwd(); |
||
73 | } |
||
74 | } |
||
75 | else { |
||
76 | $this->dataDirectory = $this->assertDirectory($data_directory); |
||
77 | } |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * Checks that a directory is valid. |
||
82 | * |
||
83 | * @param string $directory Directory. |
||
84 | * |
||
85 | * @throws \InvalidArgumentException When directory is invalid. |
||
86 | * @return string |
||
87 | */ |
||
88 | protected function assertDirectory($directory) |
||
96 | |||
97 | /** |
||
98 | * Excludes a file from coverage. |
||
99 | * |
||
100 | * @param string $file Path to file, that needs to be excluded. |
||
101 | * |
||
102 | * @return void |
||
103 | */ |
||
104 | public function excludeFile($file) |
||
108 | |||
109 | /** |
||
110 | * Starts coverage information collection. |
||
111 | * |
||
112 | * @return void |
||
113 | */ |
||
114 | public function startCollection() |
||
115 | { |
||
116 | if ( !$this->enabled() ) { |
||
117 | return; |
||
118 | } |
||
119 | |||
120 | xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Stops coverage information collection. |
||
125 | * |
||
126 | * @return void |
||
127 | */ |
||
128 | public function stopCollection() |
||
129 | { |
||
130 | if ( !$this->enabled() ) { |
||
131 | return; |
||
132 | } |
||
133 | |||
134 | $data = xdebug_get_code_coverage(); |
||
135 | xdebug_stop_code_coverage(); |
||
136 | |||
137 | foreach ( $this->excludedFiles as $file ) { |
||
138 | unset($data[$file]); |
||
139 | } |
||
140 | |||
141 | $unique_id = md5(uniqid(rand(), true)); |
||
142 | file_put_contents( |
||
143 | $name = $this->getStorageLocationPrefix() . '.' . $unique_id . '.' . $_COOKIE[self::TEST_ID_VARIABLE], |
||
144 | serialize($data) |
||
145 | ); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Determines if coverage information collection can be started. |
||
150 | * |
||
151 | * @return string |
||
152 | * @throws \RuntimeException When Xdebug extension not enabled. |
||
153 | */ |
||
154 | protected function enabled() |
||
155 | { |
||
156 | if ( !extension_loaded('xdebug') ) { |
||
157 | throw new \RuntimeException('Xdebug extension must be enabled for coverage collection'); |
||
158 | } |
||
159 | |||
160 | return isset($_COOKIE[self::TEST_ID_VARIABLE]) && !isset($_GET[self::TEST_ID_VARIABLE]); |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Returns name of the file, where coverage information will be stored. |
||
165 | * |
||
166 | * @return string |
||
167 | */ |
||
168 | protected function getStorageLocationPrefix() |
||
172 | |||
173 | /** |
||
174 | * Aggregates previously collected coverage information. |
||
175 | * |
||
176 | * @return string |
||
177 | */ |
||
178 | public function aggregateCoverageInformation() |
||
212 | |||
213 | /** |
||
214 | * Returns contents of data directory for a current test. |
||
215 | * |
||
216 | * @return array |
||
217 | */ |
||
218 | protected function getDataDirectoryFiles() |
||
224 | |||
225 | } |
||
226 |