]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - tests/PHPUnit/Util/Report/Node/File.php
Added unit tests.
[Github/sugarcrm.git] / tests / PHPUnit / Util / Report / Node / File.php
1 <?php
2 /**
3  * PHPUnit
4  *
5  * Copyright (c) 2002-2009, 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   Testing
38  * @package    PHPUnit
39  * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
40  * @copyright  2002-2009 Sebastian Bergmann <sb@sebastian-bergmann.de>
41  * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
42
43  * @link       http://www.phpunit.de/
44  * @since      File available since Release 3.2.0
45  */
46
47 require_once 'PHPUnit/Util/Filter.php';
48 require_once 'PHPUnit/Util/Filesystem.php';
49 require_once 'PHPUnit/Util/Template.php';
50 require_once 'PHPUnit/Util/Report/Node.php';
51
52 PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
53
54 /**
55  *
56  *
57  * @category   Testing
58  * @package    PHPUnit
59  * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
60  * @copyright  2002-2009 Sebastian Bergmann <sb@sebastian-bergmann.de>
61  * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
62  * @version    Release: 3.3.17
63  * @link       http://www.phpunit.de/
64  * @since      Class available since Release 3.2.0
65  */
66 class PHPUnit_Util_Report_Node_File extends PHPUnit_Util_Report_Node
67 {
68     /**
69      * @var    array
70      */
71     protected $codeLines;
72
73     /**
74      * @var    array
75      */
76     protected $codeLinesFillup = array();
77
78     /**
79      * @var    array
80      */
81     protected $executedLines;
82
83     /**
84      * @var    boolean
85      */
86     protected $yui = TRUE;
87
88     /**
89      * @var    boolean
90      */
91     protected $highlight = FALSE;
92
93     /**
94      * @var    integer
95      */
96     protected $numExecutableLines = 0;
97
98     /**
99      * @var    integer
100      */
101     protected $numExecutedLines = 0;
102
103     /**
104      * @var    array
105      */
106     protected $classes = array();
107
108     /**
109      * @var    integer
110      */
111     protected $numClasses = 0;
112
113     /**
114      * @var    integer
115      */
116     protected $numCalledClasses = 0;
117
118     /**
119      * @var    integer
120      */
121     protected $numMethods = 0;
122
123     /**
124      * @var    integer
125      */
126     protected $numCalledMethods = 0;
127
128     /**
129      * @var    string
130      */
131     protected $yuiPanelJS = '';
132
133     /**
134      * @var    array
135      */
136     protected $startLines = array();
137
138     /**
139      * @var    array
140      */
141     protected $endLines = array();
142
143     /**
144      * Constructor.
145      *
146      * @param  string                   $name
147      * @param  PHPUnit_Util_Report_Node $parent
148      * @param  array                    $executedLines
149      * @param  boolean                  $yui
150      * @param  boolean                  $highlight
151      * @throws RuntimeException
152      */
153     public function __construct($name, PHPUnit_Util_Report_Node $parent = NULL, array $executedLines, $yui = TRUE, $highlight = FALSE)
154     {
155         parent::__construct($name, $parent);
156
157         $path = $this->getPath();
158
159         if (!file_exists($path)) {
160             throw new RuntimeException;
161         }
162
163         $this->executedLines = $executedLines;
164         $this->highlight     = $highlight;
165         $this->yui           = $yui;
166         $this->codeLines     = $this->loadFile($path);
167
168         $this->calculateStatistics();
169     }
170
171     /**
172      * Returns the classes of this node.
173      *
174      * @return array
175      */
176     public function getClasses()
177     {
178         return $this->classes;
179     }
180
181     /**
182      * Returns the number of executable lines.
183      *
184      * @return integer
185      */
186     public function getNumExecutableLines()
187     {
188         return $this->numExecutableLines;
189     }
190
191     /**
192      * Returns the number of executed lines.
193      *
194      * @return integer
195      */
196     public function getNumExecutedLines()
197     {
198         return $this->numExecutedLines;
199     }
200
201     /**
202      * Returns the number of classes.
203      *
204      * @return integer
205      */
206     public function getNumClasses()
207     {
208         return $this->numClasses;
209     }
210
211     /**
212      * Returns the number of classes of which at least one method
213      * has been called at least once.
214      *
215      * @return integer
216      */
217     public function getNumCalledClasses()
218     {
219         return $this->numCalledClasses;
220     }
221
222     /**
223      * Returns the number of methods.
224      *
225      * @return integer
226      */
227     public function getNumMethods()
228     {
229         return $this->numMethods;
230     }
231
232     /**
233      * Returns the number of methods that has been called at least once.
234      *
235      * @return integer
236      */
237     public function getNumCalledMethods()
238     {
239         return $this->numCalledMethods;
240     }
241
242     /**
243      * Renders this node.
244      *
245      * @param string  $target
246      * @param string  $title
247      * @param string  $charset
248      * @param integer $lowUpperBound
249      * @param integer $highLowerBound
250      */
251     public function render($target, $title, $charset = 'ISO-8859-1', $lowUpperBound = 35, $highLowerBound = 70)
252     {
253         if ($this->yui) {
254             $template = new PHPUnit_Util_Template(
255               PHPUnit_Util_Report::$templatePath . 'file.html'
256             );
257
258             $yuiTemplate = new PHPUnit_Util_Template(
259               PHPUnit_Util_Report::$templatePath . 'yui_item.js'
260             );
261         } else {
262             $template = new PHPUnit_Util_Template(
263               PHPUnit_Util_Report::$templatePath . 'file_no_yui.html'
264             );
265         }
266
267         $i      = 1;
268         $lines  = '';
269         $ignore = FALSE;
270
271         foreach ($this->codeLines as $line) {
272             if (strpos($line, '@codeCoverageIgnore') !== FALSE) {
273                 if (strpos($line, '@codeCoverageIgnoreStart') !== FALSE) {
274                     $ignore = TRUE;
275                 }
276
277                 else if (strpos($line, '@codeCoverageIgnoreEnd') !== FALSE) {
278                     $ignore = FALSE;
279                 }
280             }
281
282             $css = '';
283
284             if (!$ignore && isset($this->executedLines[$i])) {
285                 $count = '';
286
287                 // Array: Line is executable and was executed.
288                 // count(Array) = Number of tests that hit this line.
289                 if (is_array($this->executedLines[$i])) {
290                     $color    = 'lineCov';
291                     $numTests = count($this->executedLines[$i]);
292                     $count    = sprintf('%8d', $numTests);
293
294                     if ($this->yui) {
295                         $buffer  = '';
296                         $testCSS = '';
297
298                         foreach ($this->executedLines[$i] as $test) {
299                             if (!isset($test->__liHtml)) {
300                                 $test->__liHtml = '';
301
302                                 if ($test instanceof PHPUnit_Framework_SelfDescribing) {
303                                     $testName = $test->toString();
304
305                                     if ($test instanceof PHPUnit_Framework_TestCase) {
306                                         switch ($test->getStatus()) {
307                                             case PHPUnit_Runner_BaseTestRunner::STATUS_PASSED: {
308                                                 $testCSS = ' class=\"testPassed\"';
309                                             }
310                                             break;
311
312                                             case PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE: {
313                                                 $testCSS = ' class=\"testFailure\"';
314                                             }
315                                             break;
316
317                                             case PHPUnit_Runner_BaseTestRunner::STATUS_ERROR: {
318                                                 $testCSS = ' class=\"testError\"';
319                                             }
320                                             break;
321
322                                             case PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE:
323                                             case PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED: {
324                                                 $testCSS = ' class=\"testIncomplete\"';
325                                             }
326                                             break;
327
328                                             default: {
329                                                 $testCSS = '';
330                                             }
331                                         }
332                                     }
333                                 }
334
335                                 $test->__liHtml .= sprintf(
336                                   '<li%s>%s</li>',
337
338                                   $testCSS,
339                                   addslashes(htmlspecialchars($testName))
340                                 );
341                             }
342
343                             $buffer .= $test->__liHtml;
344                         }
345
346                         if ($numTests > 1) {
347                             $header = $numTests . ' tests cover';
348                         } else {
349                             $header = '1 test covers';
350                         }
351
352                         $header .= ' line ' . $i;
353
354                         $yuiTemplate->setVar(
355                           array(
356                             'line'   => $i,
357                             'header' => $header,
358                             'tests'  => $buffer
359                           ),
360                           FALSE
361                         );
362
363                         $this->yuiPanelJS .= $yuiTemplate->render();
364                     }
365                 }
366
367                 // -1: Line is executable and was not executed.
368                 else if ($this->executedLines[$i] == -1) {
369                     $color = 'lineNoCov';
370                     $count = sprintf('%8d', 0);
371                 }
372
373                 // -2: Line is dead code.
374                 else {
375                     $color = 'lineDeadCode';
376                     $count = '        ';
377                 }
378
379                 $css = sprintf(
380                   '<span class="%s">       %s : ',
381
382                   $color,
383                   $count
384                 );
385             }
386
387             $fillup = array_shift($this->codeLinesFillup);
388
389             if ($fillup > 0) {
390                 $line .= str_repeat(' ', $fillup);
391             }
392
393             $lines .= sprintf(
394               '<span class="lineNum" id="container%d"><a name="%d"></a><a href="#%d" id="line%d">%8d</a> </span>%s%s%s' . "\n",
395
396               $i,
397               $i,
398               $i,
399               $i,
400               $i,
401               !empty($css) ? $css : '                : ',
402               !$this->highlight ? htmlspecialchars($line) : $line,
403               !empty($css) ? '</span>' : ''
404             );
405
406             $i++;
407         }
408
409         $items = '';
410
411         foreach ($this->classes as $className => $classData) {
412             $numCalledClasses     = $classData['executedLines'] > 0 ? 1   : 0;
413             $calledClassesPercent = $numCalledClasses == 1          ? 100 : 0;
414
415             $numCalledMethods = 0;
416             $numMethods       = count($classData['methods']);
417
418             foreach ($classData['methods'] as $method) {
419                 if ($method['executedLines'] > 0) {
420                     $numCalledMethods++;
421                 }
422             }
423
424             $items .= $this->doRenderItem(
425               array(
426                 'name'                 => sprintf(
427                   '<b><a href="#%d">%s</a></b>',
428
429                   $classData['startLine'],
430                   $className
431                 ),
432                 'numClasses'           => 1,
433                 'numCalledClasses'     => $numCalledClasses,
434                 'calledClassesPercent' => sprintf('%01.2f', $calledClassesPercent),
435                 'numMethods'           => $numMethods,
436                 'numCalledMethods'     => $numCalledMethods,
437                 'calledMethodsPercent' => $this->calculatePercent(
438                   $numCalledMethods, $numMethods
439                 ),
440                 'numExecutableLines'   => $classData['executableLines'],
441                 'numExecutedLines'     => $classData['executedLines'],
442                 'executedLinesPercent' => $this->calculatePercent(
443                   $classData['executedLines'], $classData['executableLines']
444                 )
445               ),
446               $lowUpperBound,
447               $highLowerBound
448             );
449
450             foreach ($classData['methods'] as $methodName => $methodData) {
451                 $numCalledMethods     = $methodData['executedLines'] > 0 ?   1 : 0;
452                 $calledMethodsPercent = $numCalledMethods == 1           ? 100 : 0;
453
454                 if ($className == '*') {
455                     $signature = PHPUnit_Util_Class::getFunctionSignature(
456                       new ReflectionFunction($methodName)
457                     );
458                 } else {
459                     $signature = PHPUnit_Util_Class::getMethodSignature(
460                       new ReflectionMethod($className, $methodName)
461                     );
462                 }
463
464                 $items .= $this->doRenderItem(
465                   array(
466                     'name'                 => sprintf(
467                       '&nbsp;<a href="#%d">%s</a>',
468
469                       $methodData['startLine'],
470                       $signature
471                     ),
472                     'numClasses'           => '',
473                     'numCalledClasses'     => '',
474                     'calledClassesPercent' => '',
475                     'numMethods'           => 1,
476                     'numCalledMethods'     => $numCalledMethods,
477                     'calledMethodsPercent' => sprintf('%01.2f', $calledMethodsPercent),
478                     'numExecutableLines'   => $methodData['executableLines'],
479                     'numExecutedLines'     => $methodData['executedLines'],
480                     'executedLinesPercent' => $this->calculatePercent(
481                       $methodData['executedLines'], $methodData['executableLines']
482                     )
483                   ),
484                   $lowUpperBound,
485                   $highLowerBound,
486                   'method_item.html'
487                 );
488             }
489         }
490
491         $this->setTemplateVars($template, $title, $charset);
492
493         $template->setVar(
494           array(
495             'lines'      => $lines,
496             'total_item' => $this->renderTotalItem($lowUpperBound, $highLowerBound, FALSE),
497             'items'      => $items,
498             'yuiPanelJS' => $this->yuiPanelJS
499           )
500         );
501
502         $cleanId = PHPUnit_Util_Filesystem::getSafeFilename($this->getId());
503         $template->renderTo($target . $cleanId . '.html');
504
505         $this->yuiPanelJS    = '';
506         $this->executedLines = array();
507     }
508
509     /**
510      * Calculates coverage statistics for the file.
511      *
512      */
513     protected function calculateStatistics()
514     {
515         $this->processClasses();
516         $this->processFunctions();
517
518         $ignoreStart = -1;
519         $lineNumber  = 1;
520
521         foreach ($this->codeLines as $line) {
522             if (isset($this->startLines[$lineNumber])) {
523                 // Start line of a class.
524                 if (isset($this->startLines[$lineNumber]['methods'])) {
525                     $currentClass = &$this->startLines[$lineNumber];
526                 }
527
528                 // Start line of a method.
529                 else {
530                     $currentMethod = &$this->startLines[$lineNumber];
531                 }
532             }
533
534             if (strpos($line, '@codeCoverageIgnore') !== FALSE) {
535                 if (strpos($line, '@codeCoverageIgnoreStart') !== FALSE) {
536                     $ignoreStart = $lineNumber;
537                 }
538
539                 else if (strpos($line, '@codeCoverageIgnoreEnd') !== FALSE) {
540                     $ignoreStart = -1;
541                 }
542             }
543
544             if (isset($this->executedLines[$lineNumber])) {
545                 // Array: Line is executable and was executed.
546                 if (is_array($this->executedLines[$lineNumber])) {
547                     if (isset($currentClass)) {
548                         $currentClass['executableLines']++;
549                         $currentClass['executedLines']++;
550                     }
551
552                     if (isset($currentMethod)) {
553                         $currentMethod['executableLines']++;
554                         $currentMethod['executedLines']++;
555                     }
556
557                     $this->numExecutableLines++;
558                     $this->numExecutedLines++;
559                 }
560
561                 // -1: Line is executable and was not executed.
562                 else if ($this->executedLines[$lineNumber] == -1) {
563                     if (isset($currentClass)) {
564                         $currentClass['executableLines']++;
565                     }
566
567                     if (isset($currentMethod)) {
568                         $currentMethod['executableLines']++;
569                     }
570
571                     $this->numExecutableLines++;
572
573                     if ($ignoreStart != -1 && $lineNumber > $ignoreStart) {
574                         if (isset($currentClass)) {
575                             $currentClass['executedLines']++;
576                         }
577
578                         if (isset($currentMethod)) {
579                             $currentMethod['executedLines']++;
580                         }
581
582                         $this->numExecutedLines++;
583                     }
584                 }
585             }
586
587             if (isset($this->endLines[$lineNumber])) {
588                 // End line of a class.
589                 if (isset($this->endLines[$lineNumber]['methods'])) {
590                     unset($currentClass);
591                 }
592
593                 // End line of a method.
594                 else {
595                     unset($currentMethod);
596                 }
597             }
598
599             $lineNumber++;
600         }
601
602         foreach ($this->classes as $class) {
603             foreach ($class['methods'] as $method) {
604                 if ($method['executedLines'] > 0) {
605                     $this->numCalledMethods++;
606                 }
607             }
608
609             if ($class['executedLines'] > 0) {
610                 $this->numCalledClasses++;
611             }
612         }
613     }
614
615     /**
616      * @author Aidan Lister <aidan@php.net>
617      * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
618      * @param  string  $file
619      * @return array
620      */
621     protected function loadFile($file)
622     {
623         $lines  = explode("\n", str_replace("\t", '    ', file_get_contents($file)));
624         $result = array();
625
626         if (count($lines) == 0) {
627             return $result;
628         }
629
630         $lines       = array_map('rtrim', $lines);
631         $linesLength = array_map('strlen', $lines);
632         $width       = max($linesLength);
633
634         foreach ($linesLength as $line => $length) {
635             $this->codeLinesFillup[$line] = $width - $length;
636         }
637
638         if (!$this->highlight) {
639             unset($lines[count($lines)-1]);
640             return $lines;
641         }
642
643         $tokens     = token_get_all(file_get_contents($file));
644         $stringFlag = FALSE;
645         $i          = 0;
646         $result[$i] = '';
647
648         foreach ($tokens as $j => $token) {
649             if (is_string($token)) {
650                 if ($token === '"' && $tokens[$j - 1] !== '\\') {
651                     $result[$i] .= sprintf(
652                       '<span class="string">%s</span>',
653
654                       htmlspecialchars($token)
655                     );
656
657                     $stringFlag = !$stringFlag;
658                 } else {
659                     $result[$i] .= sprintf(
660                       '<span class="keyword">%s</span>',
661
662                       htmlspecialchars($token)
663                     );
664                 }
665
666                 continue;
667             }
668
669             list ($token, $value) = $token;
670
671             $value = str_replace(
672               array("\t", ' '),
673               array('&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;'),
674               htmlspecialchars($value)
675             );
676
677             if ($value === "\n") {
678                 $result[++$i] = '';
679             } else {
680                 $lines = explode("\n", $value);
681
682                 foreach ($lines as $jj => $line) {
683                     $line = trim($line);
684
685                     if ($line !== '') {
686                         if ($stringFlag) {
687                             $colour = 'string';
688                         } else {
689                             switch ($token) {
690                                 case T_INLINE_HTML: {
691                                     $colour = 'html';
692                                 }
693                                 break;
694
695                                 case T_COMMENT:
696                                 case T_DOC_COMMENT: {
697                                     $colour = 'comment';
698                                 }
699                                 break;
700
701                                 case T_ABSTRACT:
702                                 case T_ARRAY:
703                                 case T_ARRAY_CAST:
704                                 case T_AS:
705                                 case T_BOOLEAN_AND:
706                                 case T_BOOLEAN_OR:
707                                 case T_BOOL_CAST:
708                                 case T_BREAK:
709                                 case T_CASE:
710                                 case T_CATCH:
711                                 case T_CLASS:
712                                 case T_CLONE:
713                                 case T_CONCAT_EQUAL:
714                                 case T_CONTINUE:
715                                 case T_DEFAULT:
716                                 case T_DOUBLE_ARROW:
717                                 case T_DOUBLE_CAST:
718                                 case T_ECHO:
719                                 case T_ELSE:
720                                 case T_ELSEIF:
721                                 case T_EMPTY:
722                                 case T_ENDDECLARE:
723                                 case T_ENDFOR:
724                                 case T_ENDFOREACH:
725                                 case T_ENDIF:
726                                 case T_ENDSWITCH:
727                                 case T_ENDWHILE:
728                                 case T_END_HEREDOC:
729                                 case T_EXIT:
730                                 case T_EXTENDS:
731                                 case T_FINAL:
732                                 case T_FOREACH:
733                                 case T_FUNCTION:
734                                 case T_GLOBAL:
735                                 case T_IF:
736                                 case T_INC:
737                                 case T_INCLUDE:
738                                 case T_INCLUDE_ONCE:
739                                 case T_INSTANCEOF:
740                                 case T_INT_CAST:
741                                 case T_ISSET:
742                                 case T_IS_EQUAL:
743                                 case T_IS_IDENTICAL:
744                                 case T_IS_NOT_IDENTICAL:
745                                 case T_IS_SMALLER_OR_EQUAL:
746                                 case T_NEW:
747                                 case T_OBJECT_CAST:
748                                 case T_OBJECT_OPERATOR:
749                                 case T_PAAMAYIM_NEKUDOTAYIM:
750                                 case T_PRIVATE:
751                                 case T_PROTECTED:
752                                 case T_PUBLIC:
753                                 case T_REQUIRE:
754                                 case T_REQUIRE_ONCE:
755                                 case T_RETURN:
756                                 case T_SL:
757                                 case T_SL_EQUAL:
758                                 case T_SR:
759                                 case T_SR_EQUAL:
760                                 case T_START_HEREDOC:
761                                 case T_STATIC:
762                                 case T_STRING_CAST:
763                                 case T_THROW:
764                                 case T_TRY:
765                                 case T_UNSET_CAST:
766                                 case T_VAR:
767                                 case T_WHILE: {
768                                     $colour = 'keyword';
769                                 }
770                                 break;
771
772                                 default: {
773                                     $colour = 'default';
774                                 }
775                             }
776                         }
777
778                         $result[$i] .= sprintf(
779                           '<span class="%s">%s</span>',
780
781                           $colour,
782                           $line
783                         );
784                     }
785
786                     if (isset($lines[$jj + 1])) {
787                         $result[++$i] = '';
788                     }
789                 }
790             }
791         }
792
793         unset($result[count($result)-1]);
794
795         return $result;
796     }
797
798     protected function processClasses()
799     {
800         $classes = PHPUnit_Util_Class::getClassesInFile($this->getPath());
801
802         foreach ($classes as $class) {
803             if (!$class->isInterface()) {
804                 $className      = $class->getName();
805                 $classStartLine = $class->getStartLine();
806                 $classEndLine   = $class->getEndLine();
807
808                 $this->classes[$className] = array(
809                   'methods'         => array(),
810                   'startLine'       => $classStartLine,
811                   'executableLines' => 0,
812                   'executedLines'   => 0
813                 );
814
815                 $this->startLines[$classStartLine] = &$this->classes[$className];
816                 $this->endLines[$classEndLine]     = &$this->classes[$className];
817
818                 foreach ($class->getMethods() as $method) {
819                     if (!$method->isAbstract() &&
820                         $method->getDeclaringClass()->getName() == $className) {
821                         $methodName      = $method->getName();
822                         $methodStartLine = $method->getStartLine();
823                         $methodEndLine   = $method->getEndLine();
824
825                         $this->classes[$className]['methods'][$methodName] = array(
826                           'startLine'       => $methodStartLine,
827                           'executableLines' => 0,
828                           'executedLines'   => 0
829                         );
830
831                         $this->startLines[$methodStartLine] = &$this->classes[$className]['methods'][$methodName];
832                         $this->endLines[$methodEndLine]     = &$this->classes[$className]['methods'][$methodName];
833
834                         $this->numMethods++;
835                     }
836                 }
837
838                 $this->numClasses++;
839             }
840         }
841     }
842
843     protected function processFunctions()
844     {
845         $functions = PHPUnit_Util_Class::getFunctionsInFile($this->getPath());
846
847         if (count($functions) > 0 && !isset($this->classes['*'])) {
848             $this->classes['*'] = array(
849               'methods'         => array(),
850               'startLine'       => 0,
851               'executableLines' => 0,
852               'executedLines'   => 0
853             );
854         }
855
856         foreach ($functions as $function) {
857             $functionName      = $function->getName();
858             $functionStartLine = $function->getStartLine();
859             $functionEndLine   = $function->getEndLine();
860
861             $this->classes['*']['methods'][$functionName] = array(
862               'startLine'       => $functionStartLine,
863               'executableLines' => 0,
864               'executedLines'   => 0
865             );
866
867             $this->startLines[$functionStartLine] = &$this->classes['*']['methods'][$functionName];
868             $this->endLines[$functionEndLine]     = &$this->classes['*']['methods'][$functionName];
869
870             $this->numMethods++;
871         }
872     }
873 }
874 ?>