]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - tests/PHPUnit/PHP/CodeCoverage/Report/HTML/Node/File.php
Add .gitignore
[Github/sugarcrm.git] / tests / PHPUnit / PHP / CodeCoverage / Report / HTML / Node / File.php
1 <?php
2 /**
3  * PHP_CodeCoverage
4  *
5  * Copyright (c) 2009-2011, Sebastian Bergmann <sb@sebastian-bergmann.de>.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *
15  *   * Redistributions in binary form must reproduce the above copyright
16  *     notice, this list of conditions and the following disclaimer in
17  *     the documentation and/or other materials provided with the
18  *     distribution.
19  *
20  *   * Neither the name of Sebastian Bergmann nor the names of his
21  *     contributors may be used to endorse or promote products derived
22  *     from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * @category   PHP
38  * @package    CodeCoverage
39  * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
40  * @copyright  2009-2011 Sebastian Bergmann <sb@sebastian-bergmann.de>
41  * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
42  * @link       http://github.com/sebastianbergmann/php-code-coverage
43  * @since      File available since Release 1.0.0
44  */
45
46 if (!defined('T_NAMESPACE')) {
47     define('T_NAMESPACE', 377);
48 }
49
50 require_once 'PHP/Token/Stream/CachingFactory.php';
51
52 /**
53  * Represents a file in the code coverage information tree.
54  *
55  * @category   PHP
56  * @package    CodeCoverage
57  * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
58  * @copyright  2009-2011 Sebastian Bergmann <sb@sebastian-bergmann.de>
59  * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
60  * @version    Release: 1.0.4
61  * @link       http://github.com/sebastianbergmann/php-code-coverage
62  * @since      Class available since Release 1.0.0
63  */
64 class PHP_CodeCoverage_Report_HTML_Node_File extends PHP_CodeCoverage_Report_HTML_Node
65 {
66     /**
67      * @var array
68      */
69     protected $codeLines;
70
71     /**
72      * @var array
73      */
74     protected $codeLinesFillup = array();
75
76     /**
77      * @var array
78      */
79     protected $executedLines;
80
81     /**
82      * @var boolean
83      */
84     protected $yui = TRUE;
85
86     /**
87      * @var boolean
88      */
89     protected $highlight = FALSE;
90
91     /**
92      * @var integer
93      */
94     protected $numExecutableLines = 0;
95
96     /**
97      * @var integer
98      */
99     protected $numExecutedLines = 0;
100
101     /**
102      * @var array
103      */
104     protected $classes = array();
105
106     /**
107      * @var integer
108      */
109     protected $numTestedClasses = 0;
110
111     /**
112      * @var integer
113      */
114     protected $numClasses = NULL;
115
116     /**
117      * @var integer
118      */
119     protected $numMethods = NULL;
120
121     /**
122      * @var integer
123      */
124     protected $numTestedMethods = NULL;
125
126     /**
127      * @var string
128      */
129     protected $yuiPanelJS = '';
130
131     /**
132      * @var array
133      */
134     protected $startLines = array();
135
136     /**
137      * @var array
138      */
139     protected $endLines = array();
140
141     /**
142      * Constructor.
143      *
144      * @param  string                            $name
145      * @param  PHP_CodeCoverage_Report_HTML_Node $parent
146      * @param  array                             $executedLines
147      * @param  boolean                           $yui
148      * @param  boolean                           $highlight
149      * @throws RuntimeException
150      */
151     public function __construct($name, PHP_CodeCoverage_Report_HTML_Node $parent, array $executedLines, $yui = TRUE, $highlight = FALSE)
152     {
153         parent::__construct($name, $parent);
154
155         $path = $this->getPath();
156
157         if (!file_exists($path)) {
158             throw new RuntimeException(
159               sprintf('Path "%s" does not exist.', $path)
160             );
161         }
162
163         $this->executedLines = $executedLines;
164         $this->highlight     = $highlight;
165         $this->yui           = $yui;
166         $this->codeLines     = $this->loadFile($path);
167         $this->ignoredLines  = PHP_CodeCoverage_Util::getLinesToBeIgnored(
168                                  $path
169                                );
170
171         $this->calculateStatistics();
172     }
173
174     /**
175      * Returns the classes of this node.
176      *
177      * @return array
178      */
179     public function getClasses()
180     {
181         return $this->classes;
182     }
183
184     /**
185      * Returns the number of executable lines.
186      *
187      * @return integer
188      */
189     public function getNumExecutableLines()
190     {
191         return $this->numExecutableLines;
192     }
193
194     /**
195      * Returns the number of executed lines.
196      *
197      * @return integer
198      */
199     public function getNumExecutedLines()
200     {
201         return $this->numExecutedLines;
202     }
203
204     /**
205      * Returns the number of classes.
206      *
207      * @return integer
208      */
209     public function getNumClasses()
210     {
211         if ($this->numClasses === NULL) {
212             $this->numClasses = count($this->classes);
213
214             if (isset($this->classes['*'])) {
215                 $this->numClasses--;
216             }
217         }
218
219         return $this->numClasses;
220     }
221
222     /**
223      * Returns the number of tested classes.
224      *
225      * @return integer
226      */
227     public function getNumTestedClasses()
228     {
229         return $this->numTestedClasses;
230     }
231
232     /**
233      * Returns the number of methods.
234      *
235      * @return integer
236      */
237     public function getNumMethods()
238     {
239         if ($this->numMethods === NULL) {
240             $this->numMethods = 0;
241
242             foreach ($this->classes as $class) {
243                 foreach ($class['methods'] as $method) {
244                     if ($method['executableLines'] > 0) {
245                         $this->numMethods++;
246                     }
247                 }
248             }
249         }
250
251         return $this->numMethods;
252     }
253
254     /**
255      * Returns the number of tested methods.
256      *
257      * @return integer
258      */
259     public function getNumTestedMethods()
260     {
261         if ($this->numTestedMethods === NULL) {
262             $this->numTestedMethods = 0;
263
264             foreach ($this->classes as $class) {
265                 foreach ($class['methods'] as $method) {
266                     if ($method['executableLines'] > 0 &&
267                         $method['coverage'] == 100) {
268                         $this->numTestedMethods++;
269                     }
270                 }
271             }
272         }
273
274         return $this->numTestedMethods;
275     }
276
277     /**
278      * Renders this node.
279      *
280      * @param string  $target
281      * @param string  $title
282      * @param string  $charset
283      * @param integer $lowUpperBound
284      * @param integer $highLowerBound
285      * @param string  $generator
286      */
287     public function render($target, $title, $charset = 'UTF-8', $lowUpperBound = 35, $highLowerBound = 70, $generator = '')
288     {
289         if ($this->yui) {
290             $template = new Text_Template(
291               PHP_CodeCoverage_Report_HTML::$templatePath . 'file.html'
292             );
293
294             $yuiTemplate = new Text_Template(
295               PHP_CodeCoverage_Report_HTML::$templatePath . 'yui_item.js'
296             );
297         } else {
298             $template = new Text_Template(
299               PHP_CodeCoverage_Report_HTML::$templatePath . 'file_no_yui.html'
300             );
301         }
302
303         $i     = 1;
304         $lines = '';
305
306         foreach ($this->codeLines as $line) {
307             $css = '';
308
309             if (!isset($this->ignoredLines[$i]) &&
310                  isset($this->executedLines[$i])) {
311                 $count = '';
312
313                 // Array: Line is executable and was executed.
314                 // count(Array) = Number of tests that hit this line.
315                 if (is_array($this->executedLines[$i])) {
316                     $color    = 'lineCov';
317                     $numTests = count($this->executedLines[$i]);
318                     $count    = sprintf('%8d', $numTests);
319
320                     if ($this->yui) {
321                         $buffer  = '';
322                         $testCSS = '';
323
324                         foreach ($this->executedLines[$i] as $test) {
325                             switch ($test['status']) {
326                                 case 0: {
327                                     $testCSS = ' class=\"testPassed\"';
328                                 }
329                                 break;
330
331                                 case 1:
332                                 case 2: {
333                                     $testCSS = ' class=\"testIncomplete\"';
334                                 }
335                                 break;
336
337                                 case 3: {
338                                     $testCSS = ' class=\"testFailure\"';
339                                 }
340                                 break;
341
342                                 case 4: {
343                                     $testCSS = ' class=\"testError\"';
344                                 }
345                                 break;
346
347                                 default: {
348                                     $testCSS = '';
349                                 }
350                             }
351
352                             $buffer .= sprintf(
353                               '<li%s>%s</li>',
354
355                               $testCSS,
356                               addslashes(htmlspecialchars($test['id']))
357                             );
358                         }
359
360                         if ($numTests > 1) {
361                             $header = $numTests . ' tests cover';
362                         } else {
363                             $header = '1 test covers';
364                         }
365
366                         $header .= ' line ' . $i;
367
368                         $yuiTemplate->setVar(
369                           array(
370                             'line'   => $i,
371                             'header' => $header,
372                             'tests'  => $buffer
373                           ),
374                           FALSE
375                         );
376
377                         $this->yuiPanelJS .= $yuiTemplate->render();
378                     }
379                 }
380
381                 // -1: Line is executable and was not executed.
382                 else if ($this->executedLines[$i] == -1) {
383                     $color = 'lineNoCov';
384                     $count = sprintf('%8d', 0);
385                 }
386
387                 // -2: Line is dead code.
388                 else {
389                     $color = 'lineDeadCode';
390                     $count = '        ';
391                 }
392
393                 $css = sprintf(
394                   '<span class="%s">       %s : ',
395
396                   $color,
397                   $count
398                 );
399             }
400
401             $fillup = array_shift($this->codeLinesFillup);
402
403             if ($fillup > 0) {
404                 $line .= str_repeat(' ', $fillup);
405             }
406
407             $lines .= sprintf(
408               '<span class="lineNum" id="container%d"><a name="%d"></a>'.
409               '<a href="#%d" id="line%d">%8d</a> </span>%s%s%s' . "\n",
410
411               $i,
412               $i,
413               $i,
414               $i,
415               $i,
416               !empty($css) ? $css : '                : ',
417               !$this->highlight ? htmlspecialchars($line) : $line,
418               !empty($css) ? '</span>' : ''
419             );
420
421             $i++;
422         }
423
424         $items = '';
425
426         foreach ($this->classes as $className => $classData) {
427             if ($classData['executedLines'] == $classData['executableLines']) {
428                 $numTestedClasses     = 1;
429                 $testedClassesPercent = 100;
430             } else {
431                 $numTestedClasses     = 0;
432                 $testedClassesPercent = 0;
433             }
434
435             $numMethods       = 0;
436             $numTestedMethods = 0;
437
438             foreach ($classData['methods'] as $method) {
439                 if ($method['executableLines'] > 0) {
440                     $numMethods++;
441
442                     if ($method['executedLines'] == $method['executableLines']) {
443                         $numTestedMethods++;
444                     }
445                 }
446             }
447
448             $items .= $this->doRenderItem(
449               array(
450                 'name'                 => sprintf(
451                   '<b><a href="#%d">%s</a></b>',
452
453                   $classData['startLine'],
454                   $className
455                 ),
456                 'numClasses'           => 1,
457                 'numTestedClasses'     => $numTestedClasses,
458                 'testedClassesPercent' => sprintf(
459                                             '%01.2f', $testedClassesPercent
460                                           ),
461                 'numMethods'           => $numMethods,
462                 'numTestedMethods'     => $numTestedMethods,
463                 'testedMethodsPercent' => PHP_CodeCoverage_Util::percent(
464                   $numTestedMethods, $numMethods, TRUE
465                 ),
466                 'numExecutableLines'   => $classData['executableLines'],
467                 'numExecutedLines'     => $classData['executedLines'],
468                 'executedLinesPercent' => PHP_CodeCoverage_Util::percent(
469                   $classData['executedLines'],
470                   $classData['executableLines'],
471                   TRUE
472                 )
473               ),
474               $lowUpperBound,
475               $highLowerBound
476             );
477
478             foreach ($classData['methods'] as $methodData) {
479                 if ($methodData['executableLines'] > 0) {
480                     if ($methodData['executedLines'] == $methodData['executableLines']) {
481                         $numTestedMethods     = 1;
482                         $testedMethodsPercent = 100;
483                     } else {
484                         $numTestedMethods     = 0;
485                         $testedMethodsPercent = 0;
486                     }
487
488                     $items .= $this->doRenderItem(
489                       array(
490                         'name'                 => sprintf(
491                           '&nbsp;<a href="#%d">%s</a>',
492
493                           $methodData['startLine'],
494                           htmlspecialchars($methodData['signature'])
495                         ),
496                         'numClasses'           => '',
497                         'numTestedClasses'     => '',
498                         'testedClassesPercent' => '',
499                         'numMethods'           => 1,
500                         'numTestedMethods'     => $numTestedMethods,
501                         'testedMethodsPercent' => sprintf(
502                                                     '%01.2f', $testedMethodsPercent
503                                                   ),
504                         'numExecutableLines'   => $methodData['executableLines'],
505                         'numExecutedLines'     => $methodData['executedLines'],
506                         'executedLinesPercent' => PHP_CodeCoverage_Util::percent(
507                           $methodData['executedLines'],
508                           $methodData['executableLines'],
509                           TRUE
510                         ),
511                         'crap'                 => PHP_CodeCoverage_Util::crap(
512                                                     $methodData['ccn'],
513                                                     PHP_CodeCoverage_Util::percent(
514                                                       $methodData['executedLines'],
515                                                       $methodData['executableLines']
516                                                     )
517                                                   )
518                       ),
519                       $lowUpperBound,
520                       $highLowerBound,
521                       'method_item.html'
522                     );
523                 }
524             }
525         }
526
527         $this->setTemplateVars($template, $title, $charset, $generator);
528
529         $template->setVar(
530           array(
531             'lines'      => $lines,
532             'total_item' => $this->renderTotalItem(
533                               $lowUpperBound, $highLowerBound, FALSE
534                             ),
535             'items'      => $items,
536             'yuiPanelJS' => $this->yuiPanelJS
537           )
538         );
539
540         $cleanId = PHP_CodeCoverage_Util::getSafeFilename($this->getId());
541         $template->renderTo($target . $cleanId . '.html');
542
543         $this->yuiPanelJS    = '';
544         $this->executedLines = array();
545     }
546
547     /**
548      * Calculates coverage statistics for the file.
549      *
550      */
551     protected function calculateStatistics()
552     {
553         $this->processClasses();
554         $this->processFunctions();
555
556         $max = count($this->codeLines);
557
558         for ($lineNumber = 1; $lineNumber <= $max; $lineNumber++) {
559             if (isset($this->startLines[$lineNumber])) {
560                 // Start line of a class.
561                 if (isset($this->startLines[$lineNumber]['methods'])) {
562                     $currentClass = &$this->startLines[$lineNumber];
563                 }
564
565                 // Start line of a method.
566                 else {
567                     $currentMethod = &$this->startLines[$lineNumber];
568                 }
569             }
570
571             if (isset($this->executedLines[$lineNumber])) {
572                 // Array: Line is executable and was executed.
573                 if (is_array($this->executedLines[$lineNumber])) {
574                     if (isset($currentClass)) {
575                         $currentClass['executableLines']++;
576                         $currentClass['executedLines']++;
577                     }
578
579                     if (isset($currentMethod)) {
580                         $currentMethod['executableLines']++;
581                         $currentMethod['executedLines']++;
582                     }
583
584                     $this->numExecutableLines++;
585                     $this->numExecutedLines++;
586                 }
587
588                 // -1: Line is executable and was not executed.
589                 else if ($this->executedLines[$lineNumber] == -1) {
590                     if (isset($currentClass)) {
591                         $currentClass['executableLines']++;
592                     }
593
594                     if (isset($currentMethod)) {
595                         $currentMethod['executableLines']++;
596                     }
597
598                     $this->numExecutableLines++;
599
600                     if (isset($this->ignoredLines[$lineNumber])) {
601                         if (isset($currentClass)) {
602                             $currentClass['executedLines']++;
603                         }
604
605                         if (isset($currentMethod)) {
606                             $currentMethod['executedLines']++;
607                         }
608
609                         $this->numExecutedLines++;
610                     }
611                 }
612             }
613
614             if (isset($this->endLines[$lineNumber])) {
615                 // End line of a class.
616                 if (isset($this->endLines[$lineNumber]['methods'])) {
617                     unset($currentClass);
618                 }
619
620                 // End line of a method.
621                 else {
622                     unset($currentMethod);
623                 }
624             }
625         }
626
627         foreach ($this->classes as $className => &$class) {
628             foreach ($class['methods'] as &$method) {
629                 if ($method['executableLines'] > 0) {
630                     $method['coverage'] = ($method['executedLines'] /
631                                            $method['executableLines']) * 100;
632                 } else {
633                     $method['coverage'] = 100;
634                 }
635
636                 $method['crap'] = PHP_CodeCoverage_Util::crap(
637                   $method['ccn'], $method['coverage']
638                 );
639
640                 $class['ccn'] += $method['ccn'];
641             }
642
643             if ($className != '*') {
644                 if ($class['executableLines'] > 0) {
645                     $class['coverage'] = ($class['executedLines'] /
646                                           $class['executableLines']) * 100;
647                 } else {
648                     $class['coverage'] = 100;
649                 }
650
651                 if ($class['coverage'] == 100) {
652                     $this->numTestedClasses++;
653                 }
654
655                 $class['crap'] = PHP_CodeCoverage_Util::crap(
656                   $class['ccn'], $class['coverage']
657                 );
658             }
659         }
660     }
661
662     /**
663      * @param  string $file
664      * @return array
665      * @author Aidan Lister <aidan@php.net>
666      */
667     protected function loadFile($file)
668     {
669         $buffer = file_get_contents($file);
670         $lines  = explode("\n", str_replace("\t", '    ', $buffer));
671         $result = array();
672
673         if (count($lines) == 0) {
674             return $result;
675         }
676
677         $lines       = array_map('rtrim', $lines);
678         $linesLength = array_map('strlen', $lines);
679         $width       = max($linesLength);
680
681         foreach ($linesLength as $line => $length) {
682             $this->codeLinesFillup[$line] = $width - $length;
683         }
684
685         if (!$this->highlight) {
686             unset($lines[count($lines)-1]);
687             return $lines;
688         }
689
690         $tokens     = token_get_all($buffer);
691         $stringFlag = FALSE;
692         $i          = 0;
693         $result[$i] = '';
694
695         foreach ($tokens as $j => $token) {
696             if (is_string($token)) {
697                 if ($token === '"' && $tokens[$j - 1] !== '\\') {
698                     $result[$i] .= sprintf(
699                       '<span class="string">%s</span>',
700
701                       htmlspecialchars($token)
702                     );
703
704                     $stringFlag = !$stringFlag;
705                 } else {
706                     $result[$i] .= sprintf(
707                       '<span class="keyword">%s</span>',
708
709                       htmlspecialchars($token)
710                     );
711                 }
712
713                 continue;
714             }
715
716             list ($token, $value) = $token;
717
718             $value = str_replace(
719               array("\t", ' '),
720               array('&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;'),
721               htmlspecialchars($value)
722             );
723
724             if ($value === "\n") {
725                 $result[++$i] = '';
726             } else {
727                 $lines = explode("\n", $value);
728
729                 foreach ($lines as $jj => $line) {
730                     $line = trim($line);
731
732                     if ($line !== '') {
733                         if ($stringFlag) {
734                             $colour = 'string';
735                         } else {
736                             switch ($token) {
737                                 case T_INLINE_HTML: {
738                                     $colour = 'html';
739                                 }
740                                 break;
741
742                                 case T_COMMENT:
743                                 case T_DOC_COMMENT: {
744                                     $colour = 'comment';
745                                 }
746                                 break;
747
748                                 case T_ABSTRACT:
749                                 case T_ARRAY:
750                                 case T_ARRAY_CAST:
751                                 case T_AS:
752                                 case T_BOOLEAN_AND:
753                                 case T_BOOLEAN_OR:
754                                 case T_BOOL_CAST:
755                                 case T_BREAK:
756                                 case T_CASE:
757                                 case T_CATCH:
758                                 case T_CLASS:
759                                 case T_CLONE:
760                                 case T_CONCAT_EQUAL:
761                                 case T_CONTINUE:
762                                 case T_DEFAULT:
763                                 case T_DOUBLE_ARROW:
764                                 case T_DOUBLE_CAST:
765                                 case T_ECHO:
766                                 case T_ELSE:
767                                 case T_ELSEIF:
768                                 case T_EMPTY:
769                                 case T_ENDDECLARE:
770                                 case T_ENDFOR:
771                                 case T_ENDFOREACH:
772                                 case T_ENDIF:
773                                 case T_ENDSWITCH:
774                                 case T_ENDWHILE:
775                                 case T_END_HEREDOC:
776                                 case T_EXIT:
777                                 case T_EXTENDS:
778                                 case T_FINAL:
779                                 case T_FOREACH:
780                                 case T_FUNCTION:
781                                 case T_GLOBAL:
782                                 case T_IF:
783                                 case T_INC:
784                                 case T_INCLUDE:
785                                 case T_INCLUDE_ONCE:
786                                 case T_INSTANCEOF:
787                                 case T_INT_CAST:
788                                 case T_ISSET:
789                                 case T_IS_EQUAL:
790                                 case T_IS_IDENTICAL:
791                                 case T_IS_NOT_IDENTICAL:
792                                 case T_IS_SMALLER_OR_EQUAL:
793                                 case T_NAMESPACE:
794                                 case T_NEW:
795                                 case T_OBJECT_CAST:
796                                 case T_OBJECT_OPERATOR:
797                                 case T_PAAMAYIM_NEKUDOTAYIM:
798                                 case T_PRIVATE:
799                                 case T_PROTECTED:
800                                 case T_PUBLIC:
801                                 case T_REQUIRE:
802                                 case T_REQUIRE_ONCE:
803                                 case T_RETURN:
804                                 case T_SL:
805                                 case T_SL_EQUAL:
806                                 case T_SR:
807                                 case T_SR_EQUAL:
808                                 case T_START_HEREDOC:
809                                 case T_STATIC:
810                                 case T_STRING_CAST:
811                                 case T_THROW:
812                                 case T_TRY:
813                                 case T_UNSET_CAST:
814                                 case T_USE:
815                                 case T_VAR:
816                                 case T_WHILE: {
817                                     $colour = 'keyword';
818                                 }
819                                 break;
820
821                                 default: {
822                                     $colour = 'default';
823                                 }
824                             }
825                         }
826
827                         $result[$i] .= sprintf(
828                           '<span class="%s">%s</span>',
829
830                           $colour,
831                           $line
832                         );
833                     }
834
835                     if (isset($lines[$jj + 1])) {
836                         $result[++$i] = '';
837                     }
838                 }
839             }
840         }
841
842         unset($result[count($result)-1]);
843
844         return $result;
845     }
846
847     protected function processClasses()
848     {
849         $file    = $this->getId() . '.html#';
850         $tokens  = PHP_Token_Stream_CachingFactory::get($this->getPath());
851         $classes = $tokens->getClasses();
852         unset($tokens);
853
854         foreach ($classes as $className => $class) {
855             $this->classes[$className] = array(
856               'methods'         => array(),
857               'startLine'       => $class['startLine'],
858               'executableLines' => 0,
859               'executedLines'   => 0,
860               'ccn'             => 0,
861               'coverage'        => 0,
862               'crap'            => 0,
863               'file'            => $file . $class['startLine']
864             );
865
866             $this->startLines[$class['startLine']] = &$this->classes[$className];
867             $this->endLines[$class['endLine']]     = &$this->classes[$className];
868
869             foreach ($class['methods'] as $methodName => $method) {
870                 $this->classes[$className]['methods'][$methodName] = array(
871                   'signature'       => $method['signature'],
872                   'startLine'       => $method['startLine'],
873                   'executableLines' => 0,
874                   'executedLines'   => 0,
875                   'ccn'             => $method['ccn'],
876                   'coverage'        => 0,
877                   'crap'            => 0,
878                   'file'            => $file . $method['startLine']
879                 );
880
881                 $this->startLines[$method['startLine']] = &$this->classes[$className]['methods'][$methodName];
882                 $this->endLines[$method['endLine']]     = &$this->classes[$className]['methods'][$methodName];
883             }
884         }
885     }
886
887     protected function processFunctions()
888     {
889         $tokens    = PHP_Token_Stream_CachingFactory::get($this->getPath());
890         $functions = $tokens->getFunctions();
891         unset($tokens);
892
893         if (count($functions) > 0 && !isset($this->classes['*'])) {
894             $this->classes['*'] = array(
895               'methods'         => array(),
896               'startLine'       => 0,
897               'executableLines' => 0,
898               'executedLines'   => 0,
899               'ccn'             => 0
900             );
901         }
902
903         foreach ($functions as $functionName => $function) {
904             $this->classes['*']['methods'][$functionName] = array(
905               'signature'       => $function['signature'],
906               'startLine'       => $function['startLine'],
907               'executableLines' => 0,
908               'executedLines'   => 0,
909               'ccn'             => $function['ccn']
910             );
911
912             $this->startLines[$function['startLine']] = &$this->classes['*']['methods'][$functionName];
913             $this->endLines[$function['endLine']]     = &$this->classes['*']['methods'][$functionName];
914         }
915     }
916 }