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\Node;
|
Chris@14
|
12
|
Chris@14
|
13 use SebastianBergmann\CodeCoverage\InvalidArgumentException;
|
Chris@14
|
14
|
Chris@14
|
15 /**
|
Chris@14
|
16 * Represents a file in the code coverage information tree.
|
Chris@14
|
17 */
|
Chris@14
|
18 class File extends AbstractNode
|
Chris@14
|
19 {
|
Chris@14
|
20 /**
|
Chris@14
|
21 * @var array
|
Chris@14
|
22 */
|
Chris@14
|
23 private $coverageData;
|
Chris@14
|
24
|
Chris@14
|
25 /**
|
Chris@14
|
26 * @var array
|
Chris@14
|
27 */
|
Chris@14
|
28 private $testData;
|
Chris@14
|
29
|
Chris@14
|
30 /**
|
Chris@14
|
31 * @var int
|
Chris@14
|
32 */
|
Chris@14
|
33 private $numExecutableLines = 0;
|
Chris@14
|
34
|
Chris@14
|
35 /**
|
Chris@14
|
36 * @var int
|
Chris@14
|
37 */
|
Chris@14
|
38 private $numExecutedLines = 0;
|
Chris@14
|
39
|
Chris@14
|
40 /**
|
Chris@14
|
41 * @var array
|
Chris@14
|
42 */
|
Chris@14
|
43 private $classes = [];
|
Chris@14
|
44
|
Chris@14
|
45 /**
|
Chris@14
|
46 * @var array
|
Chris@14
|
47 */
|
Chris@14
|
48 private $traits = [];
|
Chris@14
|
49
|
Chris@14
|
50 /**
|
Chris@14
|
51 * @var array
|
Chris@14
|
52 */
|
Chris@14
|
53 private $functions = [];
|
Chris@14
|
54
|
Chris@14
|
55 /**
|
Chris@14
|
56 * @var array
|
Chris@14
|
57 */
|
Chris@14
|
58 private $linesOfCode = [];
|
Chris@14
|
59
|
Chris@14
|
60 /**
|
Chris@14
|
61 * @var int
|
Chris@14
|
62 */
|
Chris@14
|
63 private $numClasses = null;
|
Chris@14
|
64
|
Chris@14
|
65 /**
|
Chris@14
|
66 * @var int
|
Chris@14
|
67 */
|
Chris@14
|
68 private $numTestedClasses = 0;
|
Chris@14
|
69
|
Chris@14
|
70 /**
|
Chris@14
|
71 * @var int
|
Chris@14
|
72 */
|
Chris@14
|
73 private $numTraits = null;
|
Chris@14
|
74
|
Chris@14
|
75 /**
|
Chris@14
|
76 * @var int
|
Chris@14
|
77 */
|
Chris@14
|
78 private $numTestedTraits = 0;
|
Chris@14
|
79
|
Chris@14
|
80 /**
|
Chris@14
|
81 * @var int
|
Chris@14
|
82 */
|
Chris@14
|
83 private $numMethods = null;
|
Chris@14
|
84
|
Chris@14
|
85 /**
|
Chris@14
|
86 * @var int
|
Chris@14
|
87 */
|
Chris@14
|
88 private $numTestedMethods = null;
|
Chris@14
|
89
|
Chris@14
|
90 /**
|
Chris@14
|
91 * @var int
|
Chris@14
|
92 */
|
Chris@14
|
93 private $numTestedFunctions = null;
|
Chris@14
|
94
|
Chris@14
|
95 /**
|
Chris@14
|
96 * @var array
|
Chris@14
|
97 */
|
Chris@14
|
98 private $startLines = [];
|
Chris@14
|
99
|
Chris@14
|
100 /**
|
Chris@14
|
101 * @var array
|
Chris@14
|
102 */
|
Chris@14
|
103 private $endLines = [];
|
Chris@14
|
104
|
Chris@14
|
105 /**
|
Chris@14
|
106 * @var bool
|
Chris@14
|
107 */
|
Chris@14
|
108 private $cacheTokens;
|
Chris@14
|
109
|
Chris@14
|
110 /**
|
Chris@14
|
111 * Constructor.
|
Chris@14
|
112 *
|
Chris@14
|
113 * @param string $name
|
Chris@14
|
114 * @param AbstractNode $parent
|
Chris@14
|
115 * @param array $coverageData
|
Chris@14
|
116 * @param array $testData
|
Chris@14
|
117 * @param bool $cacheTokens
|
Chris@14
|
118 *
|
Chris@14
|
119 * @throws InvalidArgumentException
|
Chris@14
|
120 */
|
Chris@14
|
121 public function __construct($name, AbstractNode $parent, array $coverageData, array $testData, $cacheTokens)
|
Chris@14
|
122 {
|
Chris@14
|
123 if (!\is_bool($cacheTokens)) {
|
Chris@14
|
124 throw InvalidArgumentException::create(
|
Chris@14
|
125 1,
|
Chris@14
|
126 'boolean'
|
Chris@14
|
127 );
|
Chris@14
|
128 }
|
Chris@14
|
129
|
Chris@14
|
130 parent::__construct($name, $parent);
|
Chris@14
|
131
|
Chris@14
|
132 $this->coverageData = $coverageData;
|
Chris@14
|
133 $this->testData = $testData;
|
Chris@14
|
134 $this->cacheTokens = $cacheTokens;
|
Chris@14
|
135
|
Chris@14
|
136 $this->calculateStatistics();
|
Chris@14
|
137 }
|
Chris@14
|
138
|
Chris@14
|
139 /**
|
Chris@14
|
140 * Returns the number of files in/under this node.
|
Chris@14
|
141 *
|
Chris@14
|
142 * @return int
|
Chris@14
|
143 */
|
Chris@14
|
144 public function count()
|
Chris@14
|
145 {
|
Chris@14
|
146 return 1;
|
Chris@14
|
147 }
|
Chris@14
|
148
|
Chris@14
|
149 /**
|
Chris@14
|
150 * Returns the code coverage data of this node.
|
Chris@14
|
151 *
|
Chris@14
|
152 * @return array
|
Chris@14
|
153 */
|
Chris@14
|
154 public function getCoverageData()
|
Chris@14
|
155 {
|
Chris@14
|
156 return $this->coverageData;
|
Chris@14
|
157 }
|
Chris@14
|
158
|
Chris@14
|
159 /**
|
Chris@14
|
160 * Returns the test data of this node.
|
Chris@14
|
161 *
|
Chris@14
|
162 * @return array
|
Chris@14
|
163 */
|
Chris@14
|
164 public function getTestData()
|
Chris@14
|
165 {
|
Chris@14
|
166 return $this->testData;
|
Chris@14
|
167 }
|
Chris@14
|
168
|
Chris@14
|
169 /**
|
Chris@14
|
170 * Returns the classes of this node.
|
Chris@14
|
171 *
|
Chris@14
|
172 * @return array
|
Chris@14
|
173 */
|
Chris@14
|
174 public function getClasses()
|
Chris@14
|
175 {
|
Chris@14
|
176 return $this->classes;
|
Chris@14
|
177 }
|
Chris@14
|
178
|
Chris@14
|
179 /**
|
Chris@14
|
180 * Returns the traits of this node.
|
Chris@14
|
181 *
|
Chris@14
|
182 * @return array
|
Chris@14
|
183 */
|
Chris@14
|
184 public function getTraits()
|
Chris@14
|
185 {
|
Chris@14
|
186 return $this->traits;
|
Chris@14
|
187 }
|
Chris@14
|
188
|
Chris@14
|
189 /**
|
Chris@14
|
190 * Returns the functions of this node.
|
Chris@14
|
191 *
|
Chris@14
|
192 * @return array
|
Chris@14
|
193 */
|
Chris@14
|
194 public function getFunctions()
|
Chris@14
|
195 {
|
Chris@14
|
196 return $this->functions;
|
Chris@14
|
197 }
|
Chris@14
|
198
|
Chris@14
|
199 /**
|
Chris@14
|
200 * Returns the LOC/CLOC/NCLOC of this node.
|
Chris@14
|
201 *
|
Chris@14
|
202 * @return array
|
Chris@14
|
203 */
|
Chris@14
|
204 public function getLinesOfCode()
|
Chris@14
|
205 {
|
Chris@14
|
206 return $this->linesOfCode;
|
Chris@14
|
207 }
|
Chris@14
|
208
|
Chris@14
|
209 /**
|
Chris@14
|
210 * Returns the number of executable lines.
|
Chris@14
|
211 *
|
Chris@14
|
212 * @return int
|
Chris@14
|
213 */
|
Chris@14
|
214 public function getNumExecutableLines()
|
Chris@14
|
215 {
|
Chris@14
|
216 return $this->numExecutableLines;
|
Chris@14
|
217 }
|
Chris@14
|
218
|
Chris@14
|
219 /**
|
Chris@14
|
220 * Returns the number of executed lines.
|
Chris@14
|
221 *
|
Chris@14
|
222 * @return int
|
Chris@14
|
223 */
|
Chris@14
|
224 public function getNumExecutedLines()
|
Chris@14
|
225 {
|
Chris@14
|
226 return $this->numExecutedLines;
|
Chris@14
|
227 }
|
Chris@14
|
228
|
Chris@14
|
229 /**
|
Chris@14
|
230 * Returns the number of classes.
|
Chris@14
|
231 *
|
Chris@14
|
232 * @return int
|
Chris@14
|
233 */
|
Chris@14
|
234 public function getNumClasses()
|
Chris@14
|
235 {
|
Chris@14
|
236 if ($this->numClasses === null) {
|
Chris@14
|
237 $this->numClasses = 0;
|
Chris@14
|
238
|
Chris@14
|
239 foreach ($this->classes as $class) {
|
Chris@14
|
240 foreach ($class['methods'] as $method) {
|
Chris@14
|
241 if ($method['executableLines'] > 0) {
|
Chris@14
|
242 $this->numClasses++;
|
Chris@14
|
243
|
Chris@14
|
244 continue 2;
|
Chris@14
|
245 }
|
Chris@14
|
246 }
|
Chris@14
|
247 }
|
Chris@14
|
248 }
|
Chris@14
|
249
|
Chris@14
|
250 return $this->numClasses;
|
Chris@14
|
251 }
|
Chris@14
|
252
|
Chris@14
|
253 /**
|
Chris@14
|
254 * Returns the number of tested classes.
|
Chris@14
|
255 *
|
Chris@14
|
256 * @return int
|
Chris@14
|
257 */
|
Chris@14
|
258 public function getNumTestedClasses()
|
Chris@14
|
259 {
|
Chris@14
|
260 return $this->numTestedClasses;
|
Chris@14
|
261 }
|
Chris@14
|
262
|
Chris@14
|
263 /**
|
Chris@14
|
264 * Returns the number of traits.
|
Chris@14
|
265 *
|
Chris@14
|
266 * @return int
|
Chris@14
|
267 */
|
Chris@14
|
268 public function getNumTraits()
|
Chris@14
|
269 {
|
Chris@14
|
270 if ($this->numTraits === null) {
|
Chris@14
|
271 $this->numTraits = 0;
|
Chris@14
|
272
|
Chris@14
|
273 foreach ($this->traits as $trait) {
|
Chris@14
|
274 foreach ($trait['methods'] as $method) {
|
Chris@14
|
275 if ($method['executableLines'] > 0) {
|
Chris@14
|
276 $this->numTraits++;
|
Chris@14
|
277
|
Chris@14
|
278 continue 2;
|
Chris@14
|
279 }
|
Chris@14
|
280 }
|
Chris@14
|
281 }
|
Chris@14
|
282 }
|
Chris@14
|
283
|
Chris@14
|
284 return $this->numTraits;
|
Chris@14
|
285 }
|
Chris@14
|
286
|
Chris@14
|
287 /**
|
Chris@14
|
288 * Returns the number of tested traits.
|
Chris@14
|
289 *
|
Chris@14
|
290 * @return int
|
Chris@14
|
291 */
|
Chris@14
|
292 public function getNumTestedTraits()
|
Chris@14
|
293 {
|
Chris@14
|
294 return $this->numTestedTraits;
|
Chris@14
|
295 }
|
Chris@14
|
296
|
Chris@14
|
297 /**
|
Chris@14
|
298 * Returns the number of methods.
|
Chris@14
|
299 *
|
Chris@14
|
300 * @return int
|
Chris@14
|
301 */
|
Chris@14
|
302 public function getNumMethods()
|
Chris@14
|
303 {
|
Chris@14
|
304 if ($this->numMethods === null) {
|
Chris@14
|
305 $this->numMethods = 0;
|
Chris@14
|
306
|
Chris@14
|
307 foreach ($this->classes as $class) {
|
Chris@14
|
308 foreach ($class['methods'] as $method) {
|
Chris@14
|
309 if ($method['executableLines'] > 0) {
|
Chris@14
|
310 $this->numMethods++;
|
Chris@14
|
311 }
|
Chris@14
|
312 }
|
Chris@14
|
313 }
|
Chris@14
|
314
|
Chris@14
|
315 foreach ($this->traits as $trait) {
|
Chris@14
|
316 foreach ($trait['methods'] as $method) {
|
Chris@14
|
317 if ($method['executableLines'] > 0) {
|
Chris@14
|
318 $this->numMethods++;
|
Chris@14
|
319 }
|
Chris@14
|
320 }
|
Chris@14
|
321 }
|
Chris@14
|
322 }
|
Chris@14
|
323
|
Chris@14
|
324 return $this->numMethods;
|
Chris@14
|
325 }
|
Chris@14
|
326
|
Chris@14
|
327 /**
|
Chris@14
|
328 * Returns the number of tested methods.
|
Chris@14
|
329 *
|
Chris@14
|
330 * @return int
|
Chris@14
|
331 */
|
Chris@14
|
332 public function getNumTestedMethods()
|
Chris@14
|
333 {
|
Chris@14
|
334 if ($this->numTestedMethods === null) {
|
Chris@14
|
335 $this->numTestedMethods = 0;
|
Chris@14
|
336
|
Chris@14
|
337 foreach ($this->classes as $class) {
|
Chris@14
|
338 foreach ($class['methods'] as $method) {
|
Chris@14
|
339 if ($method['executableLines'] > 0 &&
|
Chris@14
|
340 $method['coverage'] == 100) {
|
Chris@14
|
341 $this->numTestedMethods++;
|
Chris@14
|
342 }
|
Chris@14
|
343 }
|
Chris@14
|
344 }
|
Chris@14
|
345
|
Chris@14
|
346 foreach ($this->traits as $trait) {
|
Chris@14
|
347 foreach ($trait['methods'] as $method) {
|
Chris@14
|
348 if ($method['executableLines'] > 0 &&
|
Chris@14
|
349 $method['coverage'] == 100) {
|
Chris@14
|
350 $this->numTestedMethods++;
|
Chris@14
|
351 }
|
Chris@14
|
352 }
|
Chris@14
|
353 }
|
Chris@14
|
354 }
|
Chris@14
|
355
|
Chris@14
|
356 return $this->numTestedMethods;
|
Chris@14
|
357 }
|
Chris@14
|
358
|
Chris@14
|
359 /**
|
Chris@14
|
360 * Returns the number of functions.
|
Chris@14
|
361 *
|
Chris@14
|
362 * @return int
|
Chris@14
|
363 */
|
Chris@14
|
364 public function getNumFunctions()
|
Chris@14
|
365 {
|
Chris@14
|
366 return \count($this->functions);
|
Chris@14
|
367 }
|
Chris@14
|
368
|
Chris@14
|
369 /**
|
Chris@14
|
370 * Returns the number of tested functions.
|
Chris@14
|
371 *
|
Chris@14
|
372 * @return int
|
Chris@14
|
373 */
|
Chris@14
|
374 public function getNumTestedFunctions()
|
Chris@14
|
375 {
|
Chris@14
|
376 if ($this->numTestedFunctions === null) {
|
Chris@14
|
377 $this->numTestedFunctions = 0;
|
Chris@14
|
378
|
Chris@14
|
379 foreach ($this->functions as $function) {
|
Chris@14
|
380 if ($function['executableLines'] > 0 &&
|
Chris@14
|
381 $function['coverage'] == 100) {
|
Chris@14
|
382 $this->numTestedFunctions++;
|
Chris@14
|
383 }
|
Chris@14
|
384 }
|
Chris@14
|
385 }
|
Chris@14
|
386
|
Chris@14
|
387 return $this->numTestedFunctions;
|
Chris@14
|
388 }
|
Chris@14
|
389
|
Chris@14
|
390 /**
|
Chris@14
|
391 * Calculates coverage statistics for the file.
|
Chris@14
|
392 */
|
Chris@14
|
393 protected function calculateStatistics()
|
Chris@14
|
394 {
|
Chris@14
|
395 $classStack = $functionStack = [];
|
Chris@14
|
396
|
Chris@14
|
397 if ($this->cacheTokens) {
|
Chris@14
|
398 $tokens = \PHP_Token_Stream_CachingFactory::get($this->getPath());
|
Chris@14
|
399 } else {
|
Chris@14
|
400 $tokens = new \PHP_Token_Stream($this->getPath());
|
Chris@14
|
401 }
|
Chris@14
|
402
|
Chris@14
|
403 $this->processClasses($tokens);
|
Chris@14
|
404 $this->processTraits($tokens);
|
Chris@14
|
405 $this->processFunctions($tokens);
|
Chris@14
|
406 $this->linesOfCode = $tokens->getLinesOfCode();
|
Chris@14
|
407 unset($tokens);
|
Chris@14
|
408
|
Chris@14
|
409 for ($lineNumber = 1; $lineNumber <= $this->linesOfCode['loc']; $lineNumber++) {
|
Chris@14
|
410 if (isset($this->startLines[$lineNumber])) {
|
Chris@14
|
411 // Start line of a class.
|
Chris@14
|
412 if (isset($this->startLines[$lineNumber]['className'])) {
|
Chris@14
|
413 if (isset($currentClass)) {
|
Chris@14
|
414 $classStack[] = &$currentClass;
|
Chris@14
|
415 }
|
Chris@14
|
416
|
Chris@14
|
417 $currentClass = &$this->startLines[$lineNumber];
|
Chris@14
|
418 } // Start line of a trait.
|
Chris@14
|
419 elseif (isset($this->startLines[$lineNumber]['traitName'])) {
|
Chris@14
|
420 $currentTrait = &$this->startLines[$lineNumber];
|
Chris@14
|
421 } // Start line of a method.
|
Chris@14
|
422 elseif (isset($this->startLines[$lineNumber]['methodName'])) {
|
Chris@14
|
423 $currentMethod = &$this->startLines[$lineNumber];
|
Chris@14
|
424 } // Start line of a function.
|
Chris@14
|
425 elseif (isset($this->startLines[$lineNumber]['functionName'])) {
|
Chris@14
|
426 if (isset($currentFunction)) {
|
Chris@14
|
427 $functionStack[] = &$currentFunction;
|
Chris@14
|
428 }
|
Chris@14
|
429
|
Chris@14
|
430 $currentFunction = &$this->startLines[$lineNumber];
|
Chris@14
|
431 }
|
Chris@14
|
432 }
|
Chris@14
|
433
|
Chris@14
|
434 if (isset($this->coverageData[$lineNumber])) {
|
Chris@14
|
435 if (isset($currentClass)) {
|
Chris@14
|
436 $currentClass['executableLines']++;
|
Chris@14
|
437 }
|
Chris@14
|
438
|
Chris@14
|
439 if (isset($currentTrait)) {
|
Chris@14
|
440 $currentTrait['executableLines']++;
|
Chris@14
|
441 }
|
Chris@14
|
442
|
Chris@14
|
443 if (isset($currentMethod)) {
|
Chris@14
|
444 $currentMethod['executableLines']++;
|
Chris@14
|
445 }
|
Chris@14
|
446
|
Chris@14
|
447 if (isset($currentFunction)) {
|
Chris@14
|
448 $currentFunction['executableLines']++;
|
Chris@14
|
449 }
|
Chris@14
|
450
|
Chris@14
|
451 $this->numExecutableLines++;
|
Chris@14
|
452
|
Chris@14
|
453 if (\count($this->coverageData[$lineNumber]) > 0) {
|
Chris@14
|
454 if (isset($currentClass)) {
|
Chris@14
|
455 $currentClass['executedLines']++;
|
Chris@14
|
456 }
|
Chris@14
|
457
|
Chris@14
|
458 if (isset($currentTrait)) {
|
Chris@14
|
459 $currentTrait['executedLines']++;
|
Chris@14
|
460 }
|
Chris@14
|
461
|
Chris@14
|
462 if (isset($currentMethod)) {
|
Chris@14
|
463 $currentMethod['executedLines']++;
|
Chris@14
|
464 }
|
Chris@14
|
465
|
Chris@14
|
466 if (isset($currentFunction)) {
|
Chris@14
|
467 $currentFunction['executedLines']++;
|
Chris@14
|
468 }
|
Chris@14
|
469
|
Chris@14
|
470 $this->numExecutedLines++;
|
Chris@14
|
471 }
|
Chris@14
|
472 }
|
Chris@14
|
473
|
Chris@14
|
474 if (isset($this->endLines[$lineNumber])) {
|
Chris@14
|
475 // End line of a class.
|
Chris@14
|
476 if (isset($this->endLines[$lineNumber]['className'])) {
|
Chris@14
|
477 unset($currentClass);
|
Chris@14
|
478
|
Chris@14
|
479 if ($classStack) {
|
Chris@14
|
480 \end($classStack);
|
Chris@14
|
481 $key = \key($classStack);
|
Chris@14
|
482 $currentClass = &$classStack[$key];
|
Chris@14
|
483 unset($classStack[$key]);
|
Chris@14
|
484 }
|
Chris@14
|
485 } // End line of a trait.
|
Chris@14
|
486 elseif (isset($this->endLines[$lineNumber]['traitName'])) {
|
Chris@14
|
487 unset($currentTrait);
|
Chris@14
|
488 } // End line of a method.
|
Chris@14
|
489 elseif (isset($this->endLines[$lineNumber]['methodName'])) {
|
Chris@14
|
490 unset($currentMethod);
|
Chris@14
|
491 } // End line of a function.
|
Chris@14
|
492 elseif (isset($this->endLines[$lineNumber]['functionName'])) {
|
Chris@14
|
493 unset($currentFunction);
|
Chris@14
|
494
|
Chris@14
|
495 if ($functionStack) {
|
Chris@14
|
496 \end($functionStack);
|
Chris@14
|
497 $key = \key($functionStack);
|
Chris@14
|
498 $currentFunction = &$functionStack[$key];
|
Chris@14
|
499 unset($functionStack[$key]);
|
Chris@14
|
500 }
|
Chris@14
|
501 }
|
Chris@14
|
502 }
|
Chris@14
|
503 }
|
Chris@14
|
504
|
Chris@14
|
505 foreach ($this->traits as &$trait) {
|
Chris@14
|
506 foreach ($trait['methods'] as &$method) {
|
Chris@14
|
507 if ($method['executableLines'] > 0) {
|
Chris@14
|
508 $method['coverage'] = ($method['executedLines'] /
|
Chris@14
|
509 $method['executableLines']) * 100;
|
Chris@14
|
510 } else {
|
Chris@14
|
511 $method['coverage'] = 100;
|
Chris@14
|
512 }
|
Chris@14
|
513
|
Chris@14
|
514 $method['crap'] = $this->crap(
|
Chris@14
|
515 $method['ccn'],
|
Chris@14
|
516 $method['coverage']
|
Chris@14
|
517 );
|
Chris@14
|
518
|
Chris@14
|
519 $trait['ccn'] += $method['ccn'];
|
Chris@14
|
520 }
|
Chris@14
|
521
|
Chris@14
|
522 if ($trait['executableLines'] > 0) {
|
Chris@14
|
523 $trait['coverage'] = ($trait['executedLines'] /
|
Chris@14
|
524 $trait['executableLines']) * 100;
|
Chris@14
|
525
|
Chris@14
|
526 if ($trait['coverage'] == 100) {
|
Chris@14
|
527 $this->numTestedClasses++;
|
Chris@14
|
528 }
|
Chris@14
|
529 } else {
|
Chris@14
|
530 $trait['coverage'] = 100;
|
Chris@14
|
531 }
|
Chris@14
|
532
|
Chris@14
|
533 $trait['crap'] = $this->crap(
|
Chris@14
|
534 $trait['ccn'],
|
Chris@14
|
535 $trait['coverage']
|
Chris@14
|
536 );
|
Chris@14
|
537 }
|
Chris@14
|
538
|
Chris@14
|
539 foreach ($this->classes as &$class) {
|
Chris@14
|
540 foreach ($class['methods'] as &$method) {
|
Chris@14
|
541 if ($method['executableLines'] > 0) {
|
Chris@14
|
542 $method['coverage'] = ($method['executedLines'] /
|
Chris@14
|
543 $method['executableLines']) * 100;
|
Chris@14
|
544 } else {
|
Chris@14
|
545 $method['coverage'] = 100;
|
Chris@14
|
546 }
|
Chris@14
|
547
|
Chris@14
|
548 $method['crap'] = $this->crap(
|
Chris@14
|
549 $method['ccn'],
|
Chris@14
|
550 $method['coverage']
|
Chris@14
|
551 );
|
Chris@14
|
552
|
Chris@14
|
553 $class['ccn'] += $method['ccn'];
|
Chris@14
|
554 }
|
Chris@14
|
555
|
Chris@14
|
556 if ($class['executableLines'] > 0) {
|
Chris@14
|
557 $class['coverage'] = ($class['executedLines'] /
|
Chris@14
|
558 $class['executableLines']) * 100;
|
Chris@14
|
559
|
Chris@14
|
560 if ($class['coverage'] == 100) {
|
Chris@14
|
561 $this->numTestedClasses++;
|
Chris@14
|
562 }
|
Chris@14
|
563 } else {
|
Chris@14
|
564 $class['coverage'] = 100;
|
Chris@14
|
565 }
|
Chris@14
|
566
|
Chris@14
|
567 $class['crap'] = $this->crap(
|
Chris@14
|
568 $class['ccn'],
|
Chris@14
|
569 $class['coverage']
|
Chris@14
|
570 );
|
Chris@14
|
571 }
|
Chris@14
|
572
|
Chris@14
|
573 foreach ($this->functions as &$function) {
|
Chris@14
|
574 if ($function['executableLines'] > 0) {
|
Chris@14
|
575 $function['coverage'] = ($function['executedLines'] /
|
Chris@14
|
576 $function['executableLines']) * 100;
|
Chris@14
|
577 } else {
|
Chris@14
|
578 $function['coverage'] = 100;
|
Chris@14
|
579 }
|
Chris@14
|
580
|
Chris@14
|
581 if ($function['coverage'] == 100) {
|
Chris@14
|
582 $this->numTestedFunctions++;
|
Chris@14
|
583 }
|
Chris@14
|
584
|
Chris@14
|
585 $function['crap'] = $this->crap(
|
Chris@14
|
586 $function['ccn'],
|
Chris@14
|
587 $function['coverage']
|
Chris@14
|
588 );
|
Chris@14
|
589 }
|
Chris@14
|
590 }
|
Chris@14
|
591
|
Chris@14
|
592 /**
|
Chris@14
|
593 * @param \PHP_Token_Stream $tokens
|
Chris@14
|
594 */
|
Chris@14
|
595 protected function processClasses(\PHP_Token_Stream $tokens)
|
Chris@14
|
596 {
|
Chris@14
|
597 $classes = $tokens->getClasses();
|
Chris@14
|
598 unset($tokens);
|
Chris@14
|
599
|
Chris@14
|
600 $link = $this->getId() . '.html#';
|
Chris@14
|
601
|
Chris@14
|
602 foreach ($classes as $className => $class) {
|
Chris@14
|
603 if (!empty($class['package']['namespace'])) {
|
Chris@14
|
604 $className = $class['package']['namespace'] . '\\' . $className;
|
Chris@14
|
605 }
|
Chris@14
|
606
|
Chris@14
|
607 $this->classes[$className] = [
|
Chris@14
|
608 'className' => $className,
|
Chris@14
|
609 'methods' => [],
|
Chris@14
|
610 'startLine' => $class['startLine'],
|
Chris@14
|
611 'executableLines' => 0,
|
Chris@14
|
612 'executedLines' => 0,
|
Chris@14
|
613 'ccn' => 0,
|
Chris@14
|
614 'coverage' => 0,
|
Chris@14
|
615 'crap' => 0,
|
Chris@14
|
616 'package' => $class['package'],
|
Chris@14
|
617 'link' => $link . $class['startLine']
|
Chris@14
|
618 ];
|
Chris@14
|
619
|
Chris@14
|
620 $this->startLines[$class['startLine']] = &$this->classes[$className];
|
Chris@14
|
621 $this->endLines[$class['endLine']] = &$this->classes[$className];
|
Chris@14
|
622
|
Chris@14
|
623 foreach ($class['methods'] as $methodName => $method) {
|
Chris@14
|
624 $this->classes[$className]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);
|
Chris@14
|
625
|
Chris@14
|
626 $this->startLines[$method['startLine']] = &$this->classes[$className]['methods'][$methodName];
|
Chris@14
|
627 $this->endLines[$method['endLine']] = &$this->classes[$className]['methods'][$methodName];
|
Chris@14
|
628 }
|
Chris@14
|
629 }
|
Chris@14
|
630 }
|
Chris@14
|
631
|
Chris@14
|
632 /**
|
Chris@14
|
633 * @param \PHP_Token_Stream $tokens
|
Chris@14
|
634 */
|
Chris@14
|
635 protected function processTraits(\PHP_Token_Stream $tokens)
|
Chris@14
|
636 {
|
Chris@14
|
637 $traits = $tokens->getTraits();
|
Chris@14
|
638 unset($tokens);
|
Chris@14
|
639
|
Chris@14
|
640 $link = $this->getId() . '.html#';
|
Chris@14
|
641
|
Chris@14
|
642 foreach ($traits as $traitName => $trait) {
|
Chris@14
|
643 $this->traits[$traitName] = [
|
Chris@14
|
644 'traitName' => $traitName,
|
Chris@14
|
645 'methods' => [],
|
Chris@14
|
646 'startLine' => $trait['startLine'],
|
Chris@14
|
647 'executableLines' => 0,
|
Chris@14
|
648 'executedLines' => 0,
|
Chris@14
|
649 'ccn' => 0,
|
Chris@14
|
650 'coverage' => 0,
|
Chris@14
|
651 'crap' => 0,
|
Chris@14
|
652 'package' => $trait['package'],
|
Chris@14
|
653 'link' => $link . $trait['startLine']
|
Chris@14
|
654 ];
|
Chris@14
|
655
|
Chris@14
|
656 $this->startLines[$trait['startLine']] = &$this->traits[$traitName];
|
Chris@14
|
657 $this->endLines[$trait['endLine']] = &$this->traits[$traitName];
|
Chris@14
|
658
|
Chris@14
|
659 foreach ($trait['methods'] as $methodName => $method) {
|
Chris@14
|
660 $this->traits[$traitName]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);
|
Chris@14
|
661
|
Chris@14
|
662 $this->startLines[$method['startLine']] = &$this->traits[$traitName]['methods'][$methodName];
|
Chris@14
|
663 $this->endLines[$method['endLine']] = &$this->traits[$traitName]['methods'][$methodName];
|
Chris@14
|
664 }
|
Chris@14
|
665 }
|
Chris@14
|
666 }
|
Chris@14
|
667
|
Chris@14
|
668 /**
|
Chris@14
|
669 * @param \PHP_Token_Stream $tokens
|
Chris@14
|
670 */
|
Chris@14
|
671 protected function processFunctions(\PHP_Token_Stream $tokens)
|
Chris@14
|
672 {
|
Chris@14
|
673 $functions = $tokens->getFunctions();
|
Chris@14
|
674 unset($tokens);
|
Chris@14
|
675
|
Chris@14
|
676 $link = $this->getId() . '.html#';
|
Chris@14
|
677
|
Chris@14
|
678 foreach ($functions as $functionName => $function) {
|
Chris@14
|
679 $this->functions[$functionName] = [
|
Chris@14
|
680 'functionName' => $functionName,
|
Chris@14
|
681 'signature' => $function['signature'],
|
Chris@14
|
682 'startLine' => $function['startLine'],
|
Chris@14
|
683 'executableLines' => 0,
|
Chris@14
|
684 'executedLines' => 0,
|
Chris@14
|
685 'ccn' => $function['ccn'],
|
Chris@14
|
686 'coverage' => 0,
|
Chris@14
|
687 'crap' => 0,
|
Chris@14
|
688 'link' => $link . $function['startLine']
|
Chris@14
|
689 ];
|
Chris@14
|
690
|
Chris@14
|
691 $this->startLines[$function['startLine']] = &$this->functions[$functionName];
|
Chris@14
|
692 $this->endLines[$function['endLine']] = &$this->functions[$functionName];
|
Chris@14
|
693 }
|
Chris@14
|
694 }
|
Chris@14
|
695
|
Chris@14
|
696 /**
|
Chris@14
|
697 * Calculates the Change Risk Anti-Patterns (CRAP) index for a unit of code
|
Chris@14
|
698 * based on its cyclomatic complexity and percentage of code coverage.
|
Chris@14
|
699 *
|
Chris@14
|
700 * @param int $ccn
|
Chris@14
|
701 * @param float $coverage
|
Chris@14
|
702 *
|
Chris@14
|
703 * @return string
|
Chris@14
|
704 */
|
Chris@14
|
705 protected function crap($ccn, $coverage)
|
Chris@14
|
706 {
|
Chris@14
|
707 if ($coverage == 0) {
|
Chris@14
|
708 return (string) (\pow($ccn, 2) + $ccn);
|
Chris@14
|
709 }
|
Chris@14
|
710
|
Chris@14
|
711 if ($coverage >= 95) {
|
Chris@14
|
712 return (string) $ccn;
|
Chris@14
|
713 }
|
Chris@14
|
714
|
Chris@14
|
715 return \sprintf(
|
Chris@14
|
716 '%01.2F',
|
Chris@14
|
717 \pow($ccn, 2) * \pow(1 - $coverage / 100, 3) + $ccn
|
Chris@14
|
718 );
|
Chris@14
|
719 }
|
Chris@14
|
720
|
Chris@14
|
721 /**
|
Chris@14
|
722 * @param string $methodName
|
Chris@14
|
723 * @param array $method
|
Chris@14
|
724 * @param string $link
|
Chris@14
|
725 *
|
Chris@14
|
726 * @return array
|
Chris@14
|
727 */
|
Chris@14
|
728 private function newMethod($methodName, array $method, $link)
|
Chris@14
|
729 {
|
Chris@14
|
730 return [
|
Chris@14
|
731 'methodName' => $methodName,
|
Chris@14
|
732 'visibility' => $method['visibility'],
|
Chris@14
|
733 'signature' => $method['signature'],
|
Chris@14
|
734 'startLine' => $method['startLine'],
|
Chris@14
|
735 'endLine' => $method['endLine'],
|
Chris@14
|
736 'executableLines' => 0,
|
Chris@14
|
737 'executedLines' => 0,
|
Chris@14
|
738 'ccn' => $method['ccn'],
|
Chris@14
|
739 'coverage' => 0,
|
Chris@14
|
740 'crap' => 0,
|
Chris@14
|
741 'link' => $link . $method['startLine'],
|
Chris@14
|
742 ];
|
Chris@14
|
743 }
|
Chris@14
|
744 }
|