00001 <?php
00002
00003
00004
00005
00006
00007
00008
00015 class XmlReporter extends SimpleReporter {
00016 var $_indent;
00017 var $_namespace;
00018
00025 function XmlReporter($namespace = false, $indent = ' ') {
00026 $this->SimpleReporter();
00027 $this->_namespace = ($namespace ? $namespace . ':' : '');
00028 $this->_indent = $indent;
00029 }
00030
00038 function _getIndent($offset = 0) {
00039 return str_repeat(
00040 $this->_indent,
00041 count($this->getTestList()) + $offset);
00042 }
00043
00051 function toParsedXml($text) {
00052 return str_replace(
00053 array('&', '<', '>', '"', '\''),
00054 array('&', '<', '>', '"', '''),
00055 $text);
00056 }
00057
00064 function paintGroupStart($test_name, $size) {
00065 parent::paintGroupStart($test_name, $size);
00066 print $this->_getIndent();
00067 print "<" . $this->_namespace . "group size=\"$size\">\n";
00068 print $this->_getIndent(1);
00069 print "<" . $this->_namespace . "name>" .
00070 $this->toParsedXml($test_name) .
00071 "</" . $this->_namespace . "name>\n";
00072 }
00073
00079 function paintGroupEnd($test_name) {
00080 print $this->_getIndent();
00081 print "</" . $this->_namespace . "group>\n";
00082 parent::paintGroupEnd($test_name);
00083 }
00084
00090 function paintCaseStart($test_name) {
00091 parent::paintCaseStart($test_name);
00092 print $this->_getIndent();
00093 print "<" . $this->_namespace . "case>\n";
00094 print $this->_getIndent(1);
00095 print "<" . $this->_namespace . "name>" .
00096 $this->toParsedXml($test_name) .
00097 "</" . $this->_namespace . "name>\n";
00098 }
00099
00105 function paintCaseEnd($test_name) {
00106 print $this->_getIndent();
00107 print "</" . $this->_namespace . "case>\n";
00108 parent::paintCaseEnd($test_name);
00109 }
00110
00116 function paintMethodStart($test_name) {
00117 parent::paintMethodStart($test_name);
00118 print $this->_getIndent();
00119 print "<" . $this->_namespace . "test>\n";
00120 print $this->_getIndent(1);
00121 print "<" . $this->_namespace . "name>" .
00122 $this->toParsedXml($test_name) .
00123 "</" . $this->_namespace . "name>\n";
00124 }
00125
00132 function paintMethodEnd($test_name) {
00133 print $this->_getIndent();
00134 print "</" . $this->_namespace . "test>\n";
00135 parent::paintMethodEnd($test_name);
00136 }
00137
00143 function paintPass($message) {
00144 parent::paintPass($message);
00145 print $this->_getIndent(1);
00146 print "<" . $this->_namespace . "pass>";
00147 print $this->toParsedXml($message);
00148 print "</" . $this->_namespace . "pass>\n";
00149 }
00150
00156 function paintFail($message) {
00157 parent::paintFail($message);
00158 print $this->_getIndent(1);
00159 print "<" . $this->_namespace . "fail>";
00160 print $this->toParsedXml($message);
00161 print "</" . $this->_namespace . "fail>\n";
00162 }
00163
00169 function paintError($message) {
00170 parent::paintError($message);
00171 print $this->_getIndent(1);
00172 print "<" . $this->_namespace . "exception>";
00173 print $this->toParsedXml($message);
00174 print "</" . $this->_namespace . "exception>\n";
00175 }
00176
00182 function paintException($exception) {
00183 parent::paintException($exception);
00184 print $this->_getIndent(1);
00185 print "<" . $this->_namespace . "exception>";
00186 $message = 'Unexpected exception of type [' . get_class($exception) .
00187 '] with message [' . $exception->getMessage() .
00188 '] in [' . $exception->getFile() .
00189 ' line ' . $exception->getLine() . ']';
00190 print $this->toParsedXml($message);
00191 print "</" . $this->_namespace . "exception>\n";
00192 }
00193
00199 function paintSkip($message) {
00200 parent::paintSkip($message);
00201 print $this->_getIndent(1);
00202 print "<" . $this->_namespace . "skip>";
00203 print $this->toParsedXml($message);
00204 print "</" . $this->_namespace . "skip>\n";
00205 }
00206
00212 function paintMessage($message) {
00213 parent::paintMessage($message);
00214 print $this->_getIndent(1);
00215 print "<" . $this->_namespace . "message>";
00216 print $this->toParsedXml($message);
00217 print "</" . $this->_namespace . "message>\n";
00218 }
00219
00226 function paintFormattedMessage($message) {
00227 parent::paintFormattedMessage($message);
00228 print $this->_getIndent(1);
00229 print "<" . $this->_namespace . "formatted>";
00230 print "<![CDATA[$message]]>";
00231 print "</" . $this->_namespace . "formatted>\n";
00232 }
00233
00240 function paintSignal($type, &$payload) {
00241 parent::paintSignal($type, $payload);
00242 print $this->_getIndent(1);
00243 print "<" . $this->_namespace . "signal type=\"$type\">";
00244 print "<![CDATA[" . serialize($payload) . "]]>";
00245 print "</" . $this->_namespace . "signal>\n";
00246 }
00247
00255 function paintHeader($test_name) {
00256 if (! SimpleReporter::inCli()) {
00257 header('Content-type: text/xml');
00258 }
00259 print "<?xml version=\"1.0\"";
00260 if ($this->_namespace) {
00261 print " xmlns:" . $this->_namespace .
00262 "=\"www.lastcraft.com/SimpleTest/Beta3/Report\"";
00263 }
00264 print "?>\n";
00265 print "<" . $this->_namespace . "run>\n";
00266 }
00267
00274 function paintFooter($test_name) {
00275 print "</" . $this->_namespace . "run>\n";
00276 }
00277 }
00278
00286 class NestingXmlTag {
00287 var $_name;
00288 var $_attributes;
00289
00296 function NestingXmlTag($attributes) {
00297 $this->_name = false;
00298 $this->_attributes = $attributes;
00299 }
00300
00306 function setName($name) {
00307 $this->_name = $name;
00308 }
00309
00315 function getName() {
00316 return $this->_name;
00317 }
00318
00324 function _getAttributes() {
00325 return $this->_attributes;
00326 }
00327 }
00328
00336 class NestingMethodTag extends NestingXmlTag {
00337
00344 function NestingMethodTag($attributes) {
00345 $this->NestingXmlTag($attributes);
00346 }
00347
00354 function paintStart(&$listener) {
00355 $listener->paintMethodStart($this->getName());
00356 }
00357
00364 function paintEnd(&$listener) {
00365 $listener->paintMethodEnd($this->getName());
00366 }
00367 }
00368
00376 class NestingCaseTag extends NestingXmlTag {
00377
00384 function NestingCaseTag($attributes) {
00385 $this->NestingXmlTag($attributes);
00386 }
00387
00394 function paintStart(&$listener) {
00395 $listener->paintCaseStart($this->getName());
00396 }
00397
00404 function paintEnd(&$listener) {
00405 $listener->paintCaseEnd($this->getName());
00406 }
00407 }
00408
00416 class NestingGroupTag extends NestingXmlTag {
00417
00424 function NestingGroupTag($attributes) {
00425 $this->NestingXmlTag($attributes);
00426 }
00427
00434 function paintStart(&$listener) {
00435 $listener->paintGroupStart($this->getName(), $this->getSize());
00436 }
00437
00444 function paintEnd(&$listener) {
00445 $listener->paintGroupEnd($this->getName());
00446 }
00447
00453 function getSize() {
00454 $attributes = $this->_getAttributes();
00455 if (isset($attributes['SIZE'])) {
00456 return (integer)$attributes['SIZE'];
00457 }
00458 return 0;
00459 }
00460 }
00461
00468 class SimpleTestXmlParser {
00469 var $_listener;
00470 var $_expat;
00471 var $_tag_stack;
00472 var $_in_content_tag;
00473 var $_content;
00474 var $_attributes;
00475
00482 function SimpleTestXmlParser(&$listener) {
00483 $this->_listener = &$listener;
00484 $this->_expat = &$this->_createParser();
00485 $this->_tag_stack = array();
00486 $this->_in_content_tag = false;
00487 $this->_content = '';
00488 $this->_attributes = array();
00489 }
00490
00498 function parse($chunk) {
00499 if (! xml_parse($this->_expat, $chunk)) {
00500 trigger_error('XML parse error with ' .
00501 xml_error_string(xml_get_error_code($this->_expat)));
00502 return false;
00503 }
00504 return true;
00505 }
00506
00512 function &_createParser() {
00513 $expat = xml_parser_create();
00514 xml_set_object($expat, $this);
00515 xml_set_element_handler($expat, '_startElement', '_endElement');
00516 xml_set_character_data_handler($expat, '_addContent');
00517 xml_set_default_handler($expat, '_default');
00518 return $expat;
00519 }
00520
00527 function _pushNestingTag($nested) {
00528 array_unshift($this->_tag_stack, $nested);
00529 }
00530
00537 function &_getCurrentNestingTag() {
00538 return $this->_tag_stack[0];
00539 }
00540
00547 function _popNestingTag() {
00548 return array_shift($this->_tag_stack);
00549 }
00550
00557 function _isLeaf($tag) {
00558 return in_array($tag, array(
00559 'NAME', 'PASS', 'FAIL', 'EXCEPTION', 'SKIP', 'MESSAGE', 'FORMATTED', 'SIGNAL'));
00560 }
00561
00571 function _startElement($expat, $tag, $attributes) {
00572 $this->_attributes = $attributes;
00573 if ($tag == 'GROUP') {
00574 $this->_pushNestingTag(new NestingGroupTag($attributes));
00575 } elseif ($tag == 'CASE') {
00576 $this->_pushNestingTag(new NestingCaseTag($attributes));
00577 } elseif ($tag == 'TEST') {
00578 $this->_pushNestingTag(new NestingMethodTag($attributes));
00579 } elseif ($this->_isLeaf($tag)) {
00580 $this->_in_content_tag = true;
00581 $this->_content = '';
00582 }
00583 }
00584
00591 function _endElement($expat, $tag) {
00592 $this->_in_content_tag = false;
00593 if (in_array($tag, array('GROUP', 'CASE', 'TEST'))) {
00594 $nesting_tag = $this->_popNestingTag();
00595 $nesting_tag->paintEnd($this->_listener);
00596 } elseif ($tag == 'NAME') {
00597 $nesting_tag = &$this->_getCurrentNestingTag();
00598 $nesting_tag->setName($this->_content);
00599 $nesting_tag->paintStart($this->_listener);
00600 } elseif ($tag == 'PASS') {
00601 $this->_listener->paintPass($this->_content);
00602 } elseif ($tag == 'FAIL') {
00603 $this->_listener->paintFail($this->_content);
00604 } elseif ($tag == 'EXCEPTION') {
00605 $this->_listener->paintError($this->_content);
00606 } elseif ($tag == 'SKIP') {
00607 $this->_listener->paintSkip($this->_content);
00608 } elseif ($tag == 'SIGNAL') {
00609 $this->_listener->paintSignal(
00610 $this->_attributes['TYPE'],
00611 unserialize($this->_content));
00612 } elseif ($tag == 'MESSAGE') {
00613 $this->_listener->paintMessage($this->_content);
00614 } elseif ($tag == 'FORMATTED') {
00615 $this->_listener->paintFormattedMessage($this->_content);
00616 }
00617 }
00618
00625 function _addContent($expat, $text) {
00626 if ($this->_in_content_tag) {
00627 $this->_content .= $text;
00628 }
00629 return true;
00630 }
00631
00638 function _default($expat, $default) {
00639 }
00640 }
00641