]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - tests/PHPUnit/PHP/CodeCoverage/Report/HTML/Renderer/File.php
Merge branch 'master' of github.com:sugarcrm/sugarcrm_dev
[Github/sugarcrm.git] / tests / PHPUnit / PHP / CodeCoverage / Report / HTML / Renderer / 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.1.0
44  */
45
46 if (!defined('T_NAMESPACE')) {
47     define('T_NAMESPACE', 1000);
48 }
49
50 if (!defined('T_TRAIT')) {
51     define('T_TRAIT', 1001);
52 }
53
54 /**
55  * Renders a PHP_CodeCoverage_Report_Node_File node.
56  *
57  * @category   PHP
58  * @package    CodeCoverage
59  * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
60  * @copyright  2009-2011 Sebastian Bergmann <sb@sebastian-bergmann.de>
61  * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
62  * @version    Release: 1.1.1
63  * @link       http://github.com/sebastianbergmann/php-code-coverage
64  * @since      Class available since Release 1.1.0
65  */
66 class PHP_CodeCoverage_Report_HTML_Renderer_File extends PHP_CodeCoverage_Report_HTML_Renderer
67 {
68     /**
69      * @var boolean
70      */
71     protected $highlight;
72
73     /**
74      * @var boolean
75      */
76     protected $yui;
77
78     /**
79      * Constructor.
80      *
81      * @param string  $templatePath
82      * @param string  $charset
83      * @param string  $generator
84      * @param string  $date
85      * @param integer $lowUpperBound
86      * @param integer $highLowerBound
87      * @param boolean $highlight
88      * @param boolean $yui
89      */
90     public function __construct($templatePath, $charset, $generator, $date, $lowUpperBound, $highLowerBound, $highlight, $yui)
91     {
92         parent::__construct(
93           $templatePath,
94           $charset,
95           $generator,
96           $date,
97           $lowUpperBound,
98           $highLowerBound
99         );
100
101         $this->highlight = $highlight;
102         $this->yui       = $yui;
103     }
104
105     /**
106      * @param PHP_CodeCoverage_Report_Node_File $node
107      * @param string                            $file
108      * @param string                            $title
109      */
110     public function render(PHP_CodeCoverage_Report_Node_File $node, $file, $title = NULL)
111     {
112         if ($title === NULL) {
113             $title = $node->getName();
114         }
115
116         if ($this->yui) {
117             $template = new Text_Template($this->templatePath . 'file.html');
118         } else {
119             $template = new Text_Template(
120               $this->templatePath . 'file_no_yui.html'
121             );
122         }
123
124         list($source, $yuiTemplate) = $this->renderSource($node);
125
126         $template->setVar(
127           array(
128             'items'      => $this->renderItems($node),
129             'source'     => $source,
130             'yuiPanelJS' => $yuiTemplate
131           )
132         );
133
134         $this->setCommonTemplateVariables($template, $title, $node);
135
136         $template->renderTo($file);
137     }
138
139     /**
140      * @param  PHP_CodeCoverage_Report_Node_File $node
141      * @return string
142      */
143     protected function renderItems(PHP_CodeCoverage_Report_Node_File $node)
144     {
145         $template = new Text_Template($this->templatePath . 'file_item.html');
146
147         $methodItemTemplate = new Text_Template(
148           $this->templatePath . 'method_item.html'
149         );
150
151         $items = $this->renderItemTemplate(
152           $template,
153           array(
154             'itemClass'                    => 'coverDirectory',
155             'name'                         => 'Total',
156             'numClasses'                   => $node->getNumClasses() + $node->getNumTraits(),
157             'numTestedClasses'             => $node->getNumTestedClasses() + $node->getNumTestedTraits(),
158             'numMethods'                   => $node->getNumMethods(),
159             'numTestedMethods'             => $node->getNumTestedMethods(),
160             'linesExecutedPercent'         => $node->getLineExecutedPercent(FALSE),
161             'linesExecutedPercentAsString' => $node->getLineExecutedPercent(),
162             'numExecutedLines'             => $node->getNumExecutedLines(),
163             'numExecutableLines'           => $node->getNumExecutableLines(),
164             'testedMethodsPercent'         => $node->getTestedMethodsPercent(FALSE),
165             'testedMethodsPercentAsString' => $node->getTestedMethodsPercent(),
166             'testedClassesPercent'         => $node->getTestedClassesPercent(FALSE),
167             'testedClassesPercentAsString' => $node->getTestedClassesPercent(),
168             'crap'                         => '<acronym title="Change Risk Anti-Patterns (CRAP) Index">CRAP</acronym>'
169           )
170         );
171
172         $items .= $this->renderFunctionItems(
173           $node->getFunctions(), $methodItemTemplate
174         );
175
176         $items .= $this->renderTraitOrClassItems(
177           $node->getTraits(), $template, $methodItemTemplate
178         );
179
180         $items .= $this->renderTraitOrClassItems(
181           $node->getClasses(), $template, $methodItemTemplate
182         );
183
184         return $items;
185     }
186
187     /**
188      * @param  array         $items
189      * @param  Text_Template $template
190      * @return string
191      */
192     protected function renderTraitOrClassItems(array $items, Text_Template $template, Text_Template $methodItemTemplate)
193     {
194         if (empty($items)) {
195             return '';
196         }
197
198         $buffer = '';
199
200         foreach ($items as $name => $item) {
201             $numMethods       = count($item['methods']);
202             $numTestedMethods = 0;
203
204             foreach ($item['methods'] as $method) {
205                 if ($method['executedLines'] == $method['executableLines']) {
206                     $numTestedMethods++;
207                 }
208             }
209
210             $buffer .= $this->renderItemTemplate(
211               $template,
212               array(
213                 'itemClass'                    => 'coverDirectory',
214                 'name'                         => $name,
215                 'numClasses'                   => 1,
216                 'numTestedClasses'             => $numTestedMethods == $numMethods ? 1 : 0,
217                 'numMethods'                   => $numMethods,
218                 'numTestedMethods'             => $numTestedMethods,
219                 'linesExecutedPercent'         => PHP_CodeCoverage_Util::percent(
220                                                     $item['executedLines'],
221                                                     $item['executableLines'],
222                                                     FALSE
223                                                   ),
224                 'linesExecutedPercentAsString' => PHP_CodeCoverage_Util::percent(
225                                                     $item['executedLines'],
226                                                     $item['executableLines'],
227                                                     TRUE
228                                                   ),
229                 'numExecutedLines'             => $item['executedLines'],
230                 'numExecutableLines'           => $item['executableLines'],
231                 'testedMethodsPercent'         => PHP_CodeCoverage_Util::percent(
232                                                     $numTestedMethods,
233                                                     $numMethods,
234                                                     FALSE
235                                                   ),
236                 'testedMethodsPercentAsString' => PHP_CodeCoverage_Util::percent(
237                                                     $numTestedMethods,
238                                                     $numMethods,
239                                                     TRUE
240                                                   ),
241                 'testedClassesPercent'         => PHP_CodeCoverage_Util::percent(
242                                                     $numTestedMethods == $numMethods ? 1 : 0,
243                                                     1,
244                                                     FALSE
245                                                   ),
246                 'testedClassesPercentAsString' => PHP_CodeCoverage_Util::percent(
247                                                     $numTestedMethods == $numMethods ? 1 : 0,
248                                                     1,
249                                                     TRUE
250                                                   ),
251                 'crap'                         => $item['crap']
252               )
253             );
254
255             foreach ($item['methods'] as $method) {
256                 $buffer .= $this->renderFunctionOrMethodItem(
257                   $methodItemTemplate, $method, '&nbsp;'
258                 );
259             }
260         }
261
262         return $buffer;
263     }
264
265     /**
266      * @param  array         $functions
267      * @param  Text_Template $template
268      * @return string
269      */
270     protected function renderFunctionItems(array $functions, Text_Template $template)
271     {
272         if (empty($functions)) {
273             return '';
274         }
275
276         $buffer = '';
277
278         foreach ($functions as $function) {
279             $buffer .= $this->renderFunctionOrMethodItem(
280               $template, $function
281             );
282         }
283
284         return $buffer;
285     }
286
287     /**
288      * @param  Text_Template $template
289      * @return string
290      */
291     protected function renderFunctionOrMethodItem(Text_Template $template, array $item, $indent = '')
292     {
293         $numTestedItems = $item['executedLines'] == $item['executableLines'] ? 1 : 0;
294
295         return $this->renderItemTemplate(
296           $template,
297           array(
298             'name'                         => sprintf(
299                                                 '%s<a href="#%d">%s</a>',
300                                                 $indent,
301                                                 $item['startLine'],
302                                                 htmlspecialchars($item['signature'])
303                                               ),
304             'numMethods'                   => 1,
305             'numTestedMethods'             => $numTestedItems,
306             'linesExecutedPercent'         => PHP_CodeCoverage_Util::percent(
307                                                 $item['executedLines'],
308                                                 $item['executableLines'],
309                                                 FALSE
310                                               ),
311             'linesExecutedPercentAsString' => PHP_CodeCoverage_Util::percent(
312                                                 $item['executedLines'],
313                                                 $item['executableLines'],
314                                                 TRUE
315                                               ),
316             'numExecutedLines'             => $item['executedLines'],
317             'numExecutableLines'           => $item['executableLines'],
318             'testedMethodsPercent'         => PHP_CodeCoverage_Util::percent(
319                                                 $numTestedItems,
320                                                 1,
321                                                 FALSE
322                                               ),
323             'testedMethodsPercentAsString' => PHP_CodeCoverage_Util::percent(
324                                                 $numTestedItems,
325                                                 1,
326                                                 TRUE
327                                               ),
328             'crap'                         => $item['crap']
329           )
330         );
331     }
332
333     /**
334      * @param  PHP_CodeCoverage_Report_Node_File $node
335      * @return string
336      */
337     protected function renderSource(PHP_CodeCoverage_Report_Node_File $node)
338     {
339         if ($this->yui) {
340             $yuiTemplate = new Text_Template(
341               $this->templatePath . 'yui_item.js'
342             );
343         }
344
345         $coverageData             = $node->getCoverageData();
346         $ignoredLines             = $node->getIgnoredLines();
347         $testData                 = $node->getTestData();
348         list($codeLines, $fillup) = $this->loadFile($node->getPath());
349         $lines                    = '';
350         $yuiPanelJS               = '';
351         $i                        = 1;
352
353         foreach ($codeLines as $line) {
354             $css = '';
355
356             if (!isset($ignoredLines[$i]) && isset($coverageData[$i])) {
357                 $count    = '';
358                 $numTests = count($coverageData[$i]);
359
360                 if ($coverageData[$i] === NULL) {
361                     $color = 'lineDeadCode';
362                     $count = '        ';
363                 }
364
365                 else if ($numTests == 0) {
366                     $color = 'lineNoCov';
367                     $count = sprintf('%8d', 0);
368                 }
369
370                 else {
371                     $color = 'lineCov';
372                     $count = sprintf('%8d', $numTests);
373
374                     if ($this->yui) {
375                         $buffer  = '';
376                         $testCSS = '';
377
378                         foreach ($coverageData[$i] as $test) {
379                             switch ($testData[$test]) {
380                                 case 0: {
381                                     $testCSS = ' class=\"testPassed\"';
382                                 }
383                                 break;
384
385                                 case 1:
386                                 case 2: {
387                                     $testCSS = ' class=\"testIncomplete\"';
388                                 }
389                                 break;
390
391                                 case 3: {
392                                     $testCSS = ' class=\"testFailure\"';
393                                 }
394                                 break;
395
396                                 case 4: {
397                                     $testCSS = ' class=\"testError\"';
398                                 }
399                                 break;
400
401                                 default: {
402                                     $testCSS = '';
403                                 }
404                             }
405
406                             $buffer .= sprintf(
407                               '<li%s>%s</li>',
408
409                               $testCSS,
410                               addslashes(htmlspecialchars($test))
411                             );
412                         }
413
414                         if ($numTests > 1) {
415                             $header = $numTests . ' tests cover';
416                         } else {
417                             $header = '1 test covers';
418                         }
419
420                         $header .= ' line ' . $i;
421
422                         $yuiTemplate->setVar(
423                           array(
424                             'line'   => $i,
425                             'header' => $header,
426                             'tests'  => $buffer
427                           ),
428                           FALSE
429                         );
430
431                         $yuiPanelJS .= $yuiTemplate->render();
432                     }
433                 }
434
435                 $css = sprintf(
436                   '<span class="%s">       %s : ',
437
438                   $color,
439                   $count
440                 );
441             }
442
443             $_fillup = array_shift($fillup);
444
445             if ($_fillup > 0) {
446                 $line .= str_repeat(' ', $_fillup);
447             }
448
449             $lines .= sprintf(
450               '<span class="lineNum" id="container%d"><a name="%d"></a>'.
451               '<a href="#%d" id="line%d">%8d</a> </span>%s%s%s' . "\n",
452
453               $i,
454               $i,
455               $i,
456               $i,
457               $i,
458               !empty($css) ? $css : '                : ',
459               !$this->highlight ? htmlspecialchars($line) : $line,
460               !empty($css) ? '</span>' : ''
461             );
462
463             $i++;
464         }
465
466         return array($lines, $yuiPanelJS);
467     }
468
469     /**
470      * @param  string $file
471      * @return array
472      */
473     protected function loadFile($file)
474     {
475         $buffer = file_get_contents($file);
476         $lines  = explode("\n", str_replace("\t", '    ', $buffer));
477         $fillup = array();
478         $result = array();
479
480         if (count($lines) == 0) {
481             return $result;
482         }
483
484         $lines       = array_map('rtrim', $lines);
485         $linesLength = array_map('strlen', $lines);
486         $width       = max($linesLength);
487
488         foreach ($linesLength as $line => $length) {
489             $fillup[$line] = $width - $length;
490         }
491
492         if (!$this->highlight) {
493             unset($lines[count($lines)-1]);
494             return array($lines, $fillup);
495         }
496
497         $tokens     = token_get_all($buffer);
498         $stringFlag = FALSE;
499         $i          = 0;
500         $result[$i] = '';
501
502         foreach ($tokens as $j => $token) {
503             if (is_string($token)) {
504                 if ($token === '"' && $tokens[$j - 1] !== '\\') {
505                     $result[$i] .= sprintf(
506                       '<span class="string">%s</span>',
507
508                       htmlspecialchars($token)
509                     );
510
511                     $stringFlag = !$stringFlag;
512                 } else {
513                     $result[$i] .= sprintf(
514                       '<span class="keyword">%s</span>',
515
516                       htmlspecialchars($token)
517                     );
518                 }
519
520                 continue;
521             }
522
523             list ($token, $value) = $token;
524
525             $value = str_replace(
526               array("\t", ' '),
527               array('&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;'),
528               htmlspecialchars($value)
529             );
530
531             if ($value === "\n") {
532                 $result[++$i] = '';
533             } else {
534                 $lines = explode("\n", $value);
535
536                 foreach ($lines as $jj => $line) {
537                     $line = trim($line);
538
539                     if ($line !== '') {
540                         if ($stringFlag) {
541                             $colour = 'string';
542                         } else {
543                             switch ($token) {
544                                 case T_INLINE_HTML: {
545                                     $colour = 'html';
546                                 }
547                                 break;
548
549                                 case T_COMMENT:
550                                 case T_DOC_COMMENT: {
551                                     $colour = 'comment';
552                                 }
553                                 break;
554
555                                 case T_ABSTRACT:
556                                 case T_ARRAY:
557                                 case T_AS:
558                                 case T_BREAK:
559                                 case T_CASE:
560                                 case T_CATCH:
561                                 case T_CLASS:
562                                 case T_CLONE:
563                                 case T_CONTINUE:
564                                 case T_DEFAULT:
565                                 case T_ECHO:
566                                 case T_ELSE:
567                                 case T_ELSEIF:
568                                 case T_EMPTY:
569                                 case T_ENDDECLARE:
570                                 case T_ENDFOR:
571                                 case T_ENDFOREACH:
572                                 case T_ENDIF:
573                                 case T_ENDSWITCH:
574                                 case T_ENDWHILE:
575                                 case T_EXIT:
576                                 case T_EXTENDS:
577                                 case T_FINAL:
578                                 case T_FOREACH:
579                                 case T_FUNCTION:
580                                 case T_GLOBAL:
581                                 case T_IF:
582                                 case T_INCLUDE:
583                                 case T_INCLUDE_ONCE:
584                                 case T_INSTANCEOF:
585                                 case T_ISSET:
586                                 case T_LOGICAL_AND:
587                                 case T_LOGICAL_OR:
588                                 case T_LOGICAL_XOR:
589                                 case T_NAMESPACE:
590                                 case T_NEW:
591                                 case T_PRIVATE:
592                                 case T_PROTECTED:
593                                 case T_PUBLIC:
594                                 case T_REQUIRE:
595                                 case T_REQUIRE_ONCE:
596                                 case T_RETURN:
597                                 case T_STATIC:
598                                 case T_THROW:
599                                 case T_TRAIT:
600                                 case T_TRY:
601                                 case T_UNSET:
602                                 case T_USE:
603                                 case T_VAR:
604                                 case T_WHILE: {
605                                     $colour = 'keyword';
606                                 }
607                                 break;
608
609                                 default: {
610                                     $colour = 'default';
611                                 }
612                             }
613                         }
614
615                         $result[$i] .= sprintf(
616                           '<span class="%s">%s</span>',
617
618                           $colour,
619                           $line
620                         );
621                     }
622
623                     if (isset($lines[$jj + 1])) {
624                         $result[++$i] = '';
625                     }
626                 }
627             }
628         }
629
630         unset($result[count($result)-1]);
631
632         return array($result, $fillup);
633     }
634 }