Chris@0
|
1 <?php
|
Chris@0
|
2 /*
|
Chris@0
|
3 * This file is part of the PHP_CodeCoverage package.
|
Chris@0
|
4 *
|
Chris@0
|
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
|
Chris@0
|
6 *
|
Chris@0
|
7 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
8 * file that was distributed with this source code.
|
Chris@0
|
9 */
|
Chris@0
|
10
|
Chris@0
|
11 /**
|
Chris@0
|
12 * Factory for PHP_CodeCoverage_Report_Node_* object graphs.
|
Chris@0
|
13 *
|
Chris@0
|
14 * @since Class available since Release 1.1.0
|
Chris@0
|
15 */
|
Chris@0
|
16 class PHP_CodeCoverage_Report_Factory
|
Chris@0
|
17 {
|
Chris@0
|
18 /**
|
Chris@0
|
19 * @param PHP_CodeCoverage $coverage
|
Chris@0
|
20 * @return PHP_CodeCoverage_Report_Node_Directory
|
Chris@0
|
21 */
|
Chris@0
|
22 public function create(PHP_CodeCoverage $coverage)
|
Chris@0
|
23 {
|
Chris@0
|
24 $files = $coverage->getData();
|
Chris@0
|
25 $commonPath = $this->reducePaths($files);
|
Chris@0
|
26 $root = new PHP_CodeCoverage_Report_Node_Directory(
|
Chris@0
|
27 $commonPath,
|
Chris@0
|
28 null
|
Chris@0
|
29 );
|
Chris@0
|
30
|
Chris@0
|
31 $this->addItems(
|
Chris@0
|
32 $root,
|
Chris@0
|
33 $this->buildDirectoryStructure($files),
|
Chris@0
|
34 $coverage->getTests(),
|
Chris@0
|
35 $coverage->getCacheTokens()
|
Chris@0
|
36 );
|
Chris@0
|
37
|
Chris@0
|
38 return $root;
|
Chris@0
|
39 }
|
Chris@0
|
40
|
Chris@0
|
41 /**
|
Chris@0
|
42 * @param PHP_CodeCoverage_Report_Node_Directory $root
|
Chris@0
|
43 * @param array $items
|
Chris@0
|
44 * @param array $tests
|
Chris@0
|
45 * @param bool $cacheTokens
|
Chris@0
|
46 */
|
Chris@0
|
47 private function addItems(PHP_CodeCoverage_Report_Node_Directory $root, array $items, array $tests, $cacheTokens)
|
Chris@0
|
48 {
|
Chris@0
|
49 foreach ($items as $key => $value) {
|
Chris@0
|
50 if (substr($key, -2) == '/f') {
|
Chris@0
|
51 $key = substr($key, 0, -2);
|
Chris@0
|
52
|
Chris@0
|
53 if (file_exists($root->getPath() . DIRECTORY_SEPARATOR . $key)) {
|
Chris@0
|
54 $root->addFile($key, $value, $tests, $cacheTokens);
|
Chris@0
|
55 }
|
Chris@0
|
56 } else {
|
Chris@0
|
57 $child = $root->addDirectory($key);
|
Chris@0
|
58 $this->addItems($child, $value, $tests, $cacheTokens);
|
Chris@0
|
59 }
|
Chris@0
|
60 }
|
Chris@0
|
61 }
|
Chris@0
|
62
|
Chris@0
|
63 /**
|
Chris@0
|
64 * Builds an array representation of the directory structure.
|
Chris@0
|
65 *
|
Chris@0
|
66 * For instance,
|
Chris@0
|
67 *
|
Chris@0
|
68 * <code>
|
Chris@0
|
69 * Array
|
Chris@0
|
70 * (
|
Chris@0
|
71 * [Money.php] => Array
|
Chris@0
|
72 * (
|
Chris@0
|
73 * ...
|
Chris@0
|
74 * )
|
Chris@0
|
75 *
|
Chris@0
|
76 * [MoneyBag.php] => Array
|
Chris@0
|
77 * (
|
Chris@0
|
78 * ...
|
Chris@0
|
79 * )
|
Chris@0
|
80 * )
|
Chris@0
|
81 * </code>
|
Chris@0
|
82 *
|
Chris@0
|
83 * is transformed into
|
Chris@0
|
84 *
|
Chris@0
|
85 * <code>
|
Chris@0
|
86 * Array
|
Chris@0
|
87 * (
|
Chris@0
|
88 * [.] => Array
|
Chris@0
|
89 * (
|
Chris@0
|
90 * [Money.php] => Array
|
Chris@0
|
91 * (
|
Chris@0
|
92 * ...
|
Chris@0
|
93 * )
|
Chris@0
|
94 *
|
Chris@0
|
95 * [MoneyBag.php] => Array
|
Chris@0
|
96 * (
|
Chris@0
|
97 * ...
|
Chris@0
|
98 * )
|
Chris@0
|
99 * )
|
Chris@0
|
100 * )
|
Chris@0
|
101 * </code>
|
Chris@0
|
102 *
|
Chris@0
|
103 * @param array $files
|
Chris@0
|
104 * @return array
|
Chris@0
|
105 */
|
Chris@0
|
106 private function buildDirectoryStructure($files)
|
Chris@0
|
107 {
|
Chris@0
|
108 $result = array();
|
Chris@0
|
109
|
Chris@0
|
110 foreach ($files as $path => $file) {
|
Chris@0
|
111 $path = explode('/', $path);
|
Chris@0
|
112 $pointer = &$result;
|
Chris@0
|
113 $max = count($path);
|
Chris@0
|
114
|
Chris@0
|
115 for ($i = 0; $i < $max; $i++) {
|
Chris@0
|
116 if ($i == ($max - 1)) {
|
Chris@0
|
117 $type = '/f';
|
Chris@0
|
118 } else {
|
Chris@0
|
119 $type = '';
|
Chris@0
|
120 }
|
Chris@0
|
121
|
Chris@0
|
122 $pointer = &$pointer[$path[$i] . $type];
|
Chris@0
|
123 }
|
Chris@0
|
124
|
Chris@0
|
125 $pointer = $file;
|
Chris@0
|
126 }
|
Chris@0
|
127
|
Chris@0
|
128 return $result;
|
Chris@0
|
129 }
|
Chris@0
|
130
|
Chris@0
|
131 /**
|
Chris@0
|
132 * Reduces the paths by cutting the longest common start path.
|
Chris@0
|
133 *
|
Chris@0
|
134 * For instance,
|
Chris@0
|
135 *
|
Chris@0
|
136 * <code>
|
Chris@0
|
137 * Array
|
Chris@0
|
138 * (
|
Chris@0
|
139 * [/home/sb/Money/Money.php] => Array
|
Chris@0
|
140 * (
|
Chris@0
|
141 * ...
|
Chris@0
|
142 * )
|
Chris@0
|
143 *
|
Chris@0
|
144 * [/home/sb/Money/MoneyBag.php] => Array
|
Chris@0
|
145 * (
|
Chris@0
|
146 * ...
|
Chris@0
|
147 * )
|
Chris@0
|
148 * )
|
Chris@0
|
149 * </code>
|
Chris@0
|
150 *
|
Chris@0
|
151 * is reduced to
|
Chris@0
|
152 *
|
Chris@0
|
153 * <code>
|
Chris@0
|
154 * Array
|
Chris@0
|
155 * (
|
Chris@0
|
156 * [Money.php] => Array
|
Chris@0
|
157 * (
|
Chris@0
|
158 * ...
|
Chris@0
|
159 * )
|
Chris@0
|
160 *
|
Chris@0
|
161 * [MoneyBag.php] => Array
|
Chris@0
|
162 * (
|
Chris@0
|
163 * ...
|
Chris@0
|
164 * )
|
Chris@0
|
165 * )
|
Chris@0
|
166 * </code>
|
Chris@0
|
167 *
|
Chris@0
|
168 * @param array $files
|
Chris@0
|
169 * @return string
|
Chris@0
|
170 */
|
Chris@0
|
171 private function reducePaths(&$files)
|
Chris@0
|
172 {
|
Chris@0
|
173 if (empty($files)) {
|
Chris@0
|
174 return '.';
|
Chris@0
|
175 }
|
Chris@0
|
176
|
Chris@0
|
177 $commonPath = '';
|
Chris@0
|
178 $paths = array_keys($files);
|
Chris@0
|
179
|
Chris@0
|
180 if (count($files) == 1) {
|
Chris@0
|
181 $commonPath = dirname($paths[0]) . '/';
|
Chris@0
|
182 $files[basename($paths[0])] = $files[$paths[0]];
|
Chris@0
|
183
|
Chris@0
|
184 unset($files[$paths[0]]);
|
Chris@0
|
185
|
Chris@0
|
186 return $commonPath;
|
Chris@0
|
187 }
|
Chris@0
|
188
|
Chris@0
|
189 $max = count($paths);
|
Chris@0
|
190
|
Chris@0
|
191 for ($i = 0; $i < $max; $i++) {
|
Chris@0
|
192 // strip phar:// prefixes
|
Chris@0
|
193 if (strpos($paths[$i], 'phar://') === 0) {
|
Chris@0
|
194 $paths[$i] = substr($paths[$i], 7);
|
Chris@0
|
195 $paths[$i] = strtr($paths[$i], '/', DIRECTORY_SEPARATOR);
|
Chris@0
|
196 }
|
Chris@0
|
197 $paths[$i] = explode(DIRECTORY_SEPARATOR, $paths[$i]);
|
Chris@0
|
198
|
Chris@0
|
199 if (empty($paths[$i][0])) {
|
Chris@0
|
200 $paths[$i][0] = DIRECTORY_SEPARATOR;
|
Chris@0
|
201 }
|
Chris@0
|
202 }
|
Chris@0
|
203
|
Chris@0
|
204 $done = false;
|
Chris@0
|
205 $max = count($paths);
|
Chris@0
|
206
|
Chris@0
|
207 while (!$done) {
|
Chris@0
|
208 for ($i = 0; $i < $max - 1; $i++) {
|
Chris@0
|
209 if (!isset($paths[$i][0]) ||
|
Chris@0
|
210 !isset($paths[$i+1][0]) ||
|
Chris@0
|
211 $paths[$i][0] != $paths[$i+1][0]) {
|
Chris@0
|
212 $done = true;
|
Chris@0
|
213 break;
|
Chris@0
|
214 }
|
Chris@0
|
215 }
|
Chris@0
|
216
|
Chris@0
|
217 if (!$done) {
|
Chris@0
|
218 $commonPath .= $paths[0][0];
|
Chris@0
|
219
|
Chris@0
|
220 if ($paths[0][0] != DIRECTORY_SEPARATOR) {
|
Chris@0
|
221 $commonPath .= DIRECTORY_SEPARATOR;
|
Chris@0
|
222 }
|
Chris@0
|
223
|
Chris@0
|
224 for ($i = 0; $i < $max; $i++) {
|
Chris@0
|
225 array_shift($paths[$i]);
|
Chris@0
|
226 }
|
Chris@0
|
227 }
|
Chris@0
|
228 }
|
Chris@0
|
229
|
Chris@0
|
230 $original = array_keys($files);
|
Chris@0
|
231 $max = count($original);
|
Chris@0
|
232
|
Chris@0
|
233 for ($i = 0; $i < $max; $i++) {
|
Chris@0
|
234 $files[implode('/', $paths[$i])] = $files[$original[$i]];
|
Chris@0
|
235 unset($files[$original[$i]]);
|
Chris@0
|
236 }
|
Chris@0
|
237
|
Chris@0
|
238 ksort($files);
|
Chris@0
|
239
|
Chris@0
|
240 return substr($commonPath, 0, -1);
|
Chris@0
|
241 }
|
Chris@0
|
242 }
|