5 * Copyright (c) 2002-2009, Sebastian Bergmann <sb@sebastian-bergmann.de>.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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
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.
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.
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
43 * @link http://www.phpunit.de/
44 * @since File available since Release 3.2.0
47 require_once 'PHPUnit/Framework.php';
48 require_once 'PHPUnit/Util/Filter.php';
49 require_once 'PHPUnit/Util/Filesystem.php';
50 require_once 'PHPUnit/Util/Test.php';
52 PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
55 * Base class for nodes in the code coverage information tree.
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
66 abstract class PHPUnit_Util_Report_Node
71 protected $cache = array();
79 * @var PHPUnit_Util_Report_Node
87 * @param PHPUnit_Util_Report_Node $parent
89 public function __construct($name, PHPUnit_Util_Report_Node $parent = NULL)
92 $this->parent = $parent;
96 * Returns the percentage of classes of which at least one method
97 * has been called at least once..
101 public function getCalledClassesPercent()
103 return $this->calculatePercent(
104 $this->getNumCalledClasses(),
105 $this->getNumClasses()
110 * Returns the percentage of methods that has been called at least once.
114 public function getCalledMethodsPercent()
116 return $this->calculatePercent(
117 $this->getNumCalledMethods(),
118 $this->getNumMethods()
123 * Returns the percentage of executed lines.
127 public function getLineExecutedPercent()
129 return $this->calculatePercent(
130 $this->getNumExecutedLines(),
131 $this->getNumExecutableLines()
136 * Returns this node's ID.
140 public function getId()
142 if (!isset($this->cache['id'])) {
143 if ($this->parent === NULL) {
144 $this->cache['id'] = 'index';
146 $parentId = $this->parent->getId();
148 if ($parentId == 'index') {
149 $this->cache['id'] = $this->getName();
151 $this->cache['id'] = $parentId . '_' . $this->getName();
156 return $this->cache['id'];
160 * Returns this node's name.
162 * @param boolean $includeParent
165 public function getName($includeParent = FALSE, $includeCommonPath = FALSE)
167 if ($includeParent && $this->parent !== NULL) {
168 if (!isset($this->cache['nameIncludingParent'])) {
169 $parent = $this->parent->getName(TRUE);
170 $this->cache['nameIncludingParent'] = !empty($parent) ? $parent . '/' . $this->name : $this->name;
173 return $this->cache['nameIncludingParent'];
175 if ($this->parent !== NULL) {
178 return $includeCommonPath ? $this->name : '';
184 * Returns the link to this node.
186 * @param boolean $full
189 public function getLink($full)
191 if (substr($this->name, -1) == DIRECTORY_SEPARATOR) {
192 $name = substr($this->name, 0, -1);
197 $cleanId = PHPUnit_Util_Filesystem::getSafeFilename($this->getId());
200 if ($this->parent !== NULL) {
201 $parent = $this->parent->getLink(TRUE) . DIRECTORY_SEPARATOR;
207 '%s<a href="%s.html">%s</a>',
214 '<a href="%s.html">%s</a>',
222 * Returns this node's path.
226 public function getPath()
228 if (!isset($this->cache['path'])) {
229 if ($this->parent === NULL) {
230 $this->cache['path'] = $this->getName(FALSE, TRUE);
232 if (substr($this->parent->getPath(), -1) == DIRECTORY_SEPARATOR) {
233 $this->cache['path'] = $this->parent->getPath() .
234 $this->getName(FALSE, TRUE);
236 $this->cache['path'] = $this->parent->getPath() .
237 DIRECTORY_SEPARATOR .
238 $this->getName(FALSE, TRUE);
240 if ($this->parent->getPath() === '' &&
241 realpath($this->cache['path']) === FALSE &&
242 realpath($this->getName(FALSE, TRUE)) !== FALSE) {
243 $this->cache['path'] = $this->getName(FALSE, TRUE);
249 return $this->cache['path'];
253 * Calculates a percentage value.
257 * @return float ($a / $b) * 100
259 protected function calculatePercent($a, $b)
262 $percent = ($a / $b) * 100;
273 protected function doRenderItemObject(PHPUnit_Util_Report_Node $item, $lowUpperBound, $highLowerBound, $link = NULL, $itemClass = 'coverItem')
275 return $this->doRenderItem(
277 'name' => $link != NULL ? $link : $item->getLink(FALSE),
278 'itemClass' => $itemClass,
279 'numClasses' => $item->getNumClasses(),
280 'numCalledClasses' => $item->getNumCalledClasses(),
281 'calledClassesPercent' => $item->getCalledClassesPercent(),
282 'numMethods' => $item->getNumMethods(),
283 'numCalledMethods' => $item->getNumCalledMethods(),
284 'calledMethodsPercent' => $item->getCalledMethodsPercent(),
285 'numExecutableLines' => $item->getNumExecutableLines(),
286 'numExecutedLines' => $item->getNumExecutedLines(),
287 'executedLinesPercent' => $item->getLineExecutedPercent()
294 protected function doRenderItem(array $data, $lowUpperBound, $highLowerBound, $template = NULL)
296 if ($template === NULL) {
297 if ($this instanceof PHPUnit_Util_Report_Node_Directory) {
298 $template = 'directory_item.html';
300 $template = 'file_item.html';
304 $itemTemplate = new PHPUnit_Util_Template(
305 PHPUnit_Util_Report::$templatePath . $template
308 if ($data['numClasses'] > 0) {
309 list($classesColor, $classesLevel) = $this->getColorLevel(
310 $data['calledClassesPercent'], $lowUpperBound, $highLowerBound
313 $classesNumber = $data['numCalledClasses'] . ' / ' . $data['numClasses'];
315 $classesColor = 'snow';
316 $classesLevel = 'None';
317 $classesNumber = ' ';
320 if ($data['numMethods'] > 0) {
321 list($methodsColor, $methodsLevel) = $this->getColorLevel(
322 $data['calledMethodsPercent'], $lowUpperBound, $highLowerBound
325 $methodsNumber = $data['numCalledMethods'] . ' / ' . $data['numMethods'];
327 $methodsColor = 'snow';
328 $methodsLevel = 'None';
329 $methodsNumber = ' ';
332 list($linesColor, $linesLevel) = $this->getColorLevel(
333 $data['executedLinesPercent'], $lowUpperBound, $highLowerBound
336 if ($data['name'] == '<b><a href="#0">*</a></b>') {
342 $itemTemplate->setVar(
344 'name' => $functions ? 'Functions' : $data['name'],
345 'itemClass' => isset($data['itemClass']) ? $data['itemClass'] : 'coverItem',
346 'classes_color' => $classesColor,
347 'classes_level' => $functions ? 'None' : $classesLevel,
348 'classes_called_width' => floor($data['calledClassesPercent']),
349 'classes_called_percent' => !$functions && $data['numClasses'] > 0 ? $data['calledClassesPercent'] . '%' : ' ',
350 'classes_not_called_width' => 100 - floor($data['calledClassesPercent']),
351 'classes_number' => $functions ? ' ' : $classesNumber,
352 'methods_color' => $methodsColor,
353 'methods_level' => $methodsLevel,
354 'methods_called_width' => floor($data['calledMethodsPercent']),
355 'methods_called_percent' => $data['numMethods'] > 0 ? $data['calledMethodsPercent'] . '%' : ' ',
356 'methods_not_called_width' => 100 - floor($data['calledMethodsPercent']),
357 'methods_number' => $methodsNumber,
358 'lines_color' => $linesColor,
359 'lines_level' => $linesLevel,
360 'lines_executed_width' => floor($data['executedLinesPercent']),
361 'lines_executed_percent' => $data['executedLinesPercent'] . '%',
362 'lines_not_executed_width' => 100 - floor($data['executedLinesPercent']),
363 'num_executable_lines' => $data['numExecutableLines'],
364 'num_executed_lines' => $data['numExecutedLines']
368 return $itemTemplate->render();
371 protected function getColorLevel($percent, $lowUpperBound, $highLowerBound)
373 $floorPercent = floor($percent);
375 if ($floorPercent < $lowUpperBound) {
376 $color = 'scarlet_red';
380 else if ($floorPercent >= $lowUpperBound &&
381 $floorPercent < $highLowerBound) {
387 $color = 'chameleon';
391 return array($color, $level);
394 protected function renderTotalItem($lowUpperBound, $highLowerBound, $directory = TRUE)
396 if ($directory && empty($this->directories) && count($this->files) == 1) {
400 return $this->doRenderItemObject($this, $lowUpperBound, $highLowerBound, 'Total') .
402 ' <td class="tableHead" colspan="10"> </td>' . "\n" .
407 * @param PHPUnit_Util_Template $template
408 * @param string $title
409 * @param string $charset
411 protected function setTemplateVars(PHPUnit_Util_Template $template, $title, $charset)
416 'charset' => $charset,
417 'link' => $this->getLink(TRUE),
418 'num_executable_lines' => $this->getNumExecutableLines(),
419 'num_executed_lines' => $this->getNumExecutedLines(),
420 'lines_executed_percent' => $this->getLineExecutedPercent(),
421 'date' => $template->getDate(),
422 'phpunit_version' => PHPUnit_Runner_Version::id(),
423 'xdebug_version' => phpversion('xdebug')
429 * Returns the classes of this node.
433 abstract public function getClasses();
436 * Returns the number of executable lines.
440 abstract public function getNumExecutableLines();
443 * Returns the number of executed lines.
447 abstract public function getNumExecutedLines();
450 * Returns the number of classes.
454 abstract public function getNumClasses();
457 * Returns the number of classes of which at least one method
458 * has been called at least once.
462 abstract public function getNumCalledClasses();
465 * Returns the number of methods.
469 abstract public function getNumMethods();
472 * Returns the number of methods that has been called at least once.
476 abstract public function getNumCalledMethods();
481 * @param string $target
482 * @param string $title
483 * @param string $charset
484 * @param integer $lowUpperBound
485 * @param integer $highLowerBound
487 abstract public function render($target, $title, $charset = 'ISO-8859-1', $lowUpperBound = 35, $highLowerBound = 70);