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
>&bull
; ' . 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 \*=====================================================================*/