2 /*=====================================================================*\
3 || ###################################################################
4 || # PHPUnit2 Web Report [#]version[#]
5 || # Copyright ©2002-[#]year[#] Iris Studios, Inc.
7 || # This program is free software; you can redistribute it and/or modify
8 || # it under the terms of the GNU General Public License as published by
9 || # the Free Software Foundation; version [#]gpl[#] of the License.
11 || # This program is distributed in the hope that it will be useful, but
12 || # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 || # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 || # You should have received a copy of the GNU General Public License along
17 || # with this program; if not, write to the Free Software Foundation, Inc.,
18 || # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 || ###################################################################
20 \*=====================================================================*/
22 require_once('PHPUnit2/Framework/TestListener.php');
25 * PHPUnit2 HTML Output Generator Listener
27 * This class is used to to run PHPUnit2 tests normally and generate an
28 * HTML report at the end, which details all the tests. To use this,
29 * you need to attach this listener:
31 * <code>$result = new PHPUnit2_Framework_TestResult;
32 * $result->addListener(new ISI_PHPUnit2_Output_HTML_Listener);
33 * $suite->run($result);</code>
35 * @author Iris Studios, Inc.
36 * @copyright Copyright ©2002 - [#]year[#], Iris Studios, Inc.
40 class ISI_PHPUnit2_Output_HTML_Listener
implements PHPUnit2_Framework_TestListener
46 const TEST_SUCCESS
= 1;
52 const TEST_INCOMPLETE
= 2;
61 * An array of all the tests run in a given suite
64 protected $tests = array();
67 * An array of arrays of all the errors in a given failed test in a suite
70 protected $errors = array();
73 * An array of all the incomplete test messages for a test in a suite
76 protected $incompletes = array();
79 * Statistics for a given test suite
82 protected $stats = array();
85 * The name of the currently-running test suite
88 private $currentSuite;
91 * The name of the currently-running individual test
96 // ###################################################################
100 * @param object PHPUnit2_Framework_Test
101 * @param except Thrown execption
103 public function addError(PHPUnit2_Framework_Test
$test, Exception
$e)
105 $this->errors
[ $this->currentSuite
][ $this->currentTest
][] = new ISI_Private_Exception($e);
108 // ###################################################################
112 * @param object PHPUnit2_Framework_Test
113 * @param object PHPUnit2_Framework_AssertionFailedError
115 public function addFailure(PHPUnit2_Framework_Test
$test, PHPUnit2_Framework_AssertionFailedError
$e)
117 $this->errors
[ $this->currentSuite
][ $this->currentTest
][] = new ISI_Private_Exception($e);
118 $this->tests
[ $this->currentSuite
][ $this->currentTest
] = self
::TEST_FAIL
;
119 $this->stats
[ $this->currentSuite
]['fail']++
;
122 // ###################################################################
124 * A test reported being an incomplete implementation
126 * @param object PHPUnit2_Framework_Test
127 * @param except The thrown exception notice
129 public function addIncompleteTest(PHPUnit2_Framework_Test
$test, Exception
$e)
131 $this->incompletes
[ $this->currentSuite
][ $this->currentTest
] = new ISI_Private_Exception($e);
132 $this->tests
[ $this->currentSuite
][ $this->currentTest
] = self
::TEST_INCOMPLETE
;
133 $this->stats
[ $this->currentSuite
]['incomplete']++
;
136 // ###################################################################
140 * @param object A PHPUnit2_Framework_TestSuite
142 public function startTestSuite(PHPUnit2_Framework_TestSuite
$suite)
144 $this->currentSuite
= $suite->getName();
145 if ($this->currentSuite
== '')
150 $this->tests
[ $this->currentSuite
] = array();
151 $this->stats
[ $this->currentSuite
] = array('total' => 0, 'fail' => 0, 'incomplete' => 0);
154 // ###################################################################
158 * @param object PHPUnit2_Framework_TestSuite
160 public function endTestSuite(PHPUnit2_Framework_TestSuite
$suite)
162 $this->currentSuite
= null
;
165 // ###################################################################
167 * An individual test started
169 * @param object The PHPUnit2_Framework_Test
171 public function startTest(PHPUnit2_Framework_Test
$test)
173 $this->currentTest
= $test->getName();
174 if ($this->currentTest
== '')
179 $this->tests
[ $this->currentSuite
][ $this->currentTest
] = self
::TEST_SUCCESS
;
180 $this->stats
[ $this->currentSuite
]['total']++
;
183 // ###################################################################
185 * An individual test ended
187 * @param object The PHPUnit2_Framework_Test
189 public function endTest(PHPUnit2_Framework_Test
$test)
191 $this->currentTest
= null
;
194 // ###################################################################
196 * Destructor: create the HTML output
198 public function __destruct()
200 $stats = array('total' => 0, 'incomplete' => 0, 'fail' => 0, 'success' => 0);
201 foreach ($this->stats
AS $statGroup)
203 foreach ($statGroup AS $statType => $count)
205 $stats["$statType"] +
= $count;
208 $stats['success'] = $stats['total'] - ($stats['incomplete'] +
$stats['fail']);
210 $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
211 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
212 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
214 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
215 <title>Unit Test Results</title>
217 <style type="text/css">
223 font-family: "Trebuchet MS", Verdana, Helvetica, sans-serif;
228 background-color: rgb(255, 255, 255);
230 border-color: rgb(222, 222, 222);
237 background-color: rgb(222, 222, 222);
252 border-color: rgb(222, 230, 255);
253 border-style: dashed;
261 background-color: rgb(222, 230, 255);
269 color: rgb(111, 133, 255);
274 border-color: rgb(216, 255, 216);
275 border-style: dashed;
283 background-color: rgb(216, 255, 216);
291 color: rgb(76, 168, 78);
296 border-color: rgb(255, 226, 229);
297 border-style: dashed;
305 background-color: rgb(255, 226, 229);
313 color: rgb(168, 65, 63);
343 <h1>Unit Test Results</h1>
346 <div>The following is a report of how each unit test performed. If any errors or exceptions were thrown, they have been recorded below. Tests have been broken down into their test suite groups. Your overall statistics are here:</div>
350 <div>Total Tests: <strong>' . $stats['total'] . '</strong></div>
351 <div>Number Success: <strong class="greenText">' . $stats['success'] . '</strong></div>
352 <div>Number Fail: <strong class="redText">' . $stats['fail'] . '</strong></div>
353 <div>Number Incomplete: <strong class="blueText">' . $stats['incomplete'] . '</strong></div>
357 <div><em>Total Success Rate: <strong class="' . ($stats['success'] == $stats['total'] ?
'green' : 'red') . 'Text">' . round(100 * ($stats['success'] / $stats['total']), 1) . '%</strong></em></div>
364 foreach ($this->tests
AS $suite => $tests)
366 $successPercent = round(100 * (($this->stats
["$suite"]['total'] - ($this->stats
["$suite"]['fail'] +
$this->stats
["$suite"]['incomplete'])) / $this->stats
["$suite"]['total']), 1);
368 $output .= '<div class="suite">';
369 $output .= "\n\t" . '<div class="suiteHead">';
370 $output .= "\n\t\t" . '<span style="float: right">' . $this->stats
["$suite"]['total'] . ' Tests, ' . $successPercent . '% Success' . '</span>';
371 $output .= "\n\t\t" . $suite;
372 $output .= "\n\t" . '</div>';
373 $output .= "\n\t" . '<div class="testGroup">';
374 foreach ($tests AS $name => $statusCode)
378 case self
::TEST_SUCCESS
:
379 $cssName = 'Success';
385 case self
::TEST_INCOMPLETE
:
386 $cssName = 'Incomplete';
389 $info = $this->formatInfo($this->incompletes
["$suite"]["$name"]);
392 case self
::TEST_FAIL
:
396 $info = $this->formatInfo($this->errors
["$suite"]["$name"]);
400 $output .= "\n\t\t" . '<div class="test' . $cssName . ' ' . $cssColor . 'Text' . ($info ?
' negateMargin' : '') . '">';
401 $output .= "\n\t\t\t" . '<div class="test' . $cssName . 'Head">' . $name . '</div>';
405 $output .= "\n\t\t\t" . '<div class="textPadding">';
407 $output .= "\n\t\t\t" . '</div class="textPadding">';
410 $output .= "\n\t\t" . '</div>';
412 $output .= "\n\t" . '</div>';
413 $output .= "\n" . '</div>';
414 $output .= "\n\n" . '<br />' . "\n\n";
421 file_put_contents('./UnitTestReport.html', $output);
424 // ###################################################################
426 * Formats an error array into a bulleted list
428 * @param mixed Error/information list
430 * @return string Formatted HTML
432 private function formatInfo($list)
434 if (!is_array($list))
436 $list = array($list);
439 $count = sizeof($list);
440 foreach ($list AS $exc)
444 if ($exc->getMessage() != '')
446 $output = "\n\t\t\t\t" . '<div class="message' . ($count == $i ?
' messageLast' : '') . '">';
447 $output .= "\n\t\t\t\t\t" . '<div>• ' . htmlspecialchars($exc->getMessage()) . '</div>';
450 $output .= "\n\t\t\t\t\t" . '<div class="location">in ' . $exc->getPath() . ' at line ' . $exc->getLine() . '</div>';
452 if ($exc->getMessage() != '')
454 $output .= "\n\t\t\t\t" . '</div>';
463 * Iris Studios Private Exception Handler
465 * This class is just a form of an exception that ignores the stack trace
466 * because it's too long.
468 * @author Iris Studios, Inc.
469 * @copyright Copyright ©2002 - [#]year[#], Iris Studios, Inc.
470 * @version $Revision$
473 class ISI_Private_Exception
476 * Exception context message
479 private $message = '';
488 * Line number of the exception
493 // ###################################################################
495 * Constructor: accept exception
497 * @param except A given exception
499 public function __construct(Exception
$e)
501 $this->message
= $e->getMessage();
502 $this->path
= $e->getFile();
503 $this->line
= $e->getLine();
506 // ###################################################################
508 * Returns the context message
510 * @return string Context message
512 public function getMessage()
514 return $this->message
;
517 // ###################################################################
519 * Returns the file path
521 * @return string File path
523 public function getPath()
528 // ###################################################################
530 * Returns the line number
532 * @return integer Line number
534 public function getLine()
540 /*=====================================================================*\
541 || ###################################################################
544 || ###################################################################
545 \*=====================================================================*/