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