Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/*** base include file for SimpleTest* @package SimpleTest* @subpackage UnitTester* @version $Id: xml.php 1398 2006-09-08 19:31:03Z xue $*//**#@+* include other SimpleTest class files*/require_once(dirname(__FILE__) . '/scorer.php');/**#@-*//*** Creates the XML needed for remote communication* by SimpleTest.* @package SimpleTest* @subpackage UnitTester*/class XmlReporter extends SimpleReporter {protected $_indent;protected $_namespace;/*** Does nothing yet.* @access public*/function XmlReporter($namespace = false, $indent = ' ') {$this->SimpleReporter();$this->_namespace = ($namespace ? $namespace . ':' : '');$this->_indent = $indent;}/*** Calculates the pretty printing indent level* from the current level of nesting.* @param integer $offset Extra indenting level.* @return string Leading space.* @access protected*/function _getIndent($offset = 0) {return str_repeat($this->_indent,count($this->getTestList()) + $offset);}/*** Converts character string to parsed XML* entities string.* @param string text Unparsed character data.* @return string Parsed character data.* @access public*/function toParsedXml($text) {return str_replace(array('&', '<', '>', '"', '\''),array('&', '<', '>', '"', '''),$text);}/*** Paints the start of a group test.* @param string $test_name Name of test that is starting.* @param integer $size Number of test cases starting.* @access public*/function paintGroupStart($test_name, $size) {parent::paintGroupStart($test_name, $size);print $this->_getIndent();print "<" . $this->_namespace . "group size=\"$size\">\n";print $this->_getIndent(1);print "<" . $this->_namespace . "name>" .$this->toParsedXml($test_name) ."</" . $this->_namespace . "name>\n";}/*** Paints the end of a group test.* @param string $test_name Name of test that is ending.* @access public*/function paintGroupEnd($test_name) {print $this->_getIndent();print "</" . $this->_namespace . "group>\n";parent::paintGroupEnd($test_name);}/*** Paints the start of a test case.* @param string $test_name Name of test that is starting.* @access public*/function paintCaseStart($test_name) {parent::paintCaseStart($test_name);print $this->_getIndent();print "<" . $this->_namespace . "case>\n";print $this->_getIndent(1);print "<" . $this->_namespace . "name>" .$this->toParsedXml($test_name) ."</" . $this->_namespace . "name>\n";}/*** Paints the end of a test case.* @param string $test_name Name of test that is ending.* @access public*/function paintCaseEnd($test_name) {print $this->_getIndent();print "</" . $this->_namespace . "case>\n";parent::paintCaseEnd($test_name);}/*** Paints the start of a test method.* @param string $test_name Name of test that is starting.* @access public*/function paintMethodStart($test_name) {parent::paintMethodStart($test_name);print $this->_getIndent();print "<" . $this->_namespace . "test>\n";print $this->_getIndent(1);print "<" . $this->_namespace . "name>" .$this->toParsedXml($test_name) ."</" . $this->_namespace . "name>\n";}/*** Paints the end of a test method.* @param string $test_name Name of test that is ending.* @param integer $progress Number of test cases ending.* @access public*/function paintMethodEnd($test_name) {print $this->_getIndent();print "</" . $this->_namespace . "test>\n";parent::paintMethodEnd($test_name);}/*** Increments the pass count.* @param string $message Message is ignored.* @access public*/function paintPass($message) {parent::paintPass($message);print $this->_getIndent(1);print "<" . $this->_namespace . "pass>";print $this->toParsedXml($message);print "</" . $this->_namespace . "pass>\n";}/*** Increments the fail count.* @param string $message Message is ignored.* @access public*/function paintFail($message) {parent::paintFail($message);print $this->_getIndent(1);print "<" . $this->_namespace . "fail>";print $this->toParsedXml($message);print "</" . $this->_namespace . "fail>\n";}/*** Paints a PHP error or exception.* @param string $message Message is ignored.* @access public* @abstract*/function paintError($message) {parent::paintError($message);print $this->_getIndent(1);print "<" . $this->_namespace . "exception>";print $this->toParsedXml($message);print "</" . $this->_namespace . "exception>\n";}/*** Paints a simple supplementary message.* @param string $message Text to display.* @access public*/function paintMessage($message) {parent::paintMessage($message);print $this->_getIndent(1);print "<" . $this->_namespace . "message>";print $this->toParsedXml($message);print "</" . $this->_namespace . "message>\n";}/*** Paints a formatted ASCII message such as a* variable dump.* @param string $message Text to display.* @access public*/function paintFormattedMessage($message) {parent::paintFormattedMessage($message);print $this->_getIndent(1);print "<" . $this->_namespace . "formatted>";print "<![CDATA[$message]]>";print "</" . $this->_namespace . "formatted>\n";}/*** Serialises the event object.* @param string $type Event type as text.* @param mixed $payload Message or object.* @access public*/function paintSignal($type, $payload) {parent::paintSignal($type, $payload);print $this->_getIndent(1);print "<" . $this->_namespace . "signal type=\"$type\">";print "<![CDATA[" . serialize($payload) . "]]>";print "</" . $this->_namespace . "signal>\n";}/*** Paints the test document header.* @param string $test_name First test top level* to start.* @access public* @abstract*/function paintHeader($test_name) {if (! SimpleReporter::inCli()) {header('Content-type: text/xml');}print "<?xml version=\"1.0\"";if ($this->_namespace) {print " xmlns:" . $this->_namespace ."=\"www.lastcraft.com/SimpleTest/Beta3/Report\"";}print "?>\n";print "<" . $this->_namespace . "run>\n";}/*** Paints the test document footer.* @param string $test_name The top level test.* @access public* @abstract*/function paintFooter($test_name) {print "</" . $this->_namespace . "run>\n";}}/*** Accumulator for incoming tag. Holds the* incoming test structure information for* later dispatch to the reporter.* @package SimpleTest* @subpackage UnitTester*/class NestingXmlTag {protected $_name;protected $_attributes;/*** Sets the basic test information except* the name.* @param hash $attributes Name value pairs.* @access public*/function NestingXmlTag($attributes) {$this->_name = false;$this->_attributes = $attributes;}/*** Sets the test case/method name.* @param string $name Name of test.* @access public*/function setName($name) {$this->_name = $name;}/*** Accessor for name.* @return string Name of test.* @access public*/function getName() {return $this->_name;}/*** Accessor for attributes.* @return hash All attributes.* @access protected*/function _getAttributes() {return $this->_attributes;}}/*** Accumulator for incoming method tag. Holds the* incoming test structure information for* later dispatch to the reporter.* @package SimpleTest* @subpackage UnitTester*/class NestingMethodTag extends NestingXmlTag {/*** Sets the basic test information except* the name.* @param hash $attributes Name value pairs.* @access public*/function NestingMethodTag($attributes) {$this->NestingXmlTag($attributes);}/*** Signals the appropriate start event on the* listener.* @param SimpleReporter $listener Target for events.* @access public*/function paintStart($listener) {$listener->paintMethodStart($this->getName());}/*** Signals the appropriate end event on the* listener.* @param SimpleReporter $listener Target for events.* @access public*/function paintEnd($listener) {$listener->paintMethodEnd($this->getName());}}/*** Accumulator for incoming case tag. Holds the* incoming test structure information for* later dispatch to the reporter.* @package SimpleTest* @subpackage UnitTester*/class NestingCaseTag extends NestingXmlTag {/*** Sets the basic test information except* the name.* @param hash $attributes Name value pairs.* @access public*/function NestingCaseTag($attributes) {$this->NestingXmlTag($attributes);}/*** Signals the appropriate start event on the* listener.* @param SimpleReporter $listener Target for events.* @access public*/function paintStart($listener) {$listener->paintCaseStart($this->getName());}/*** Signals the appropriate end event on the* listener.* @param SimpleReporter $listener Target for events.* @access public*/function paintEnd($listener) {$listener->paintCaseEnd($this->getName());}}/*** Accumulator for incoming group tag. Holds the* incoming test structure information for* later dispatch to the reporter.* @package SimpleTest* @subpackage UnitTester*/class NestingGroupTag extends NestingXmlTag {/*** Sets the basic test information except* the name.* @param hash $attributes Name value pairs.* @access public*/function NestingGroupTag($attributes) {$this->NestingXmlTag($attributes);}/*** Signals the appropriate start event on the* listener.* @param SimpleReporter $listener Target for events.* @access public*/function paintStart($listener) {$listener->paintGroupStart($this->getName(), $this->getSize());}/*** Signals the appropriate end event on the* listener.* @param SimpleReporter $listener Target for events.* @access public*/function paintEnd($listener) {$listener->paintGroupEnd($this->getName());}/*** The size in the attributes.* @return integer Value of size attribute or zero.* @access public*/function getSize() {$attributes = $this->_getAttributes();if (isset($attributes['SIZE'])) {return (integer)$attributes['SIZE'];}return 0;}}/*** Parser for importing the output of the XmlReporter.* Dispatches that output to another reporter.* @package SimpleTest* @subpackage UnitTester*/class SimpleTestXmlParser {protected $_listener;protected $_expat;protected $_tag_stack;protected $_in_content_tag;protected $_content;protected $_attributes;/*** Loads a listener with the SimpleReporter* interface.* @param SimpleReporter $listener Listener of tag events.* @access public*/function SimpleTestXmlParser($listener) {$this->_listener = $listener;$this->_expat = $this->_createParser();$this->_tag_stack = array();$this->_in_content_tag = false;$this->_content = '';$this->_attributes = array();}/*** Parses a block of XML sending the results to* the listener.* @param string $chunk Block of text to read.* @return boolean True if valid XML.* @access public*/function parse($chunk) {if (! xml_parse($this->_expat, $chunk)) {trigger_error('XML parse error with ' .xml_error_string(xml_get_error_code($this->_expat)));return false;}return true;}/*** Sets up expat as the XML parser.* @return resource Expat handle.* @access protected*/function &_createParser() {$expat = xml_parser_create();xml_set_object($expat, $this);xml_set_element_handler($expat, '_startElement', '_endElement');xml_set_character_data_handler($expat, '_addContent');xml_set_default_handler($expat, '_default');return $expat;}/*** Opens a new test nesting level.* @return NestedXmlTag The group, case or method tag* to start.* @access private*/function _pushNestingTag($nested) {array_unshift($this->_tag_stack, $nested);}/*** Accessor for current test structure tag.* @return NestedXmlTag The group, case or method tag* being parsed.* @access private*/function &_getCurrentNestingTag() {return $this->_tag_stack[0];}/*** Ends a nesting tag.* @return NestedXmlTag The group, case or method tag* just finished.* @access private*/function _popNestingTag() {return array_shift($this->_tag_stack);}/*** Test if tag is a leaf node with only text content.* @param string $tag XML tag name.* @return @boolean True if leaf, false if nesting.* @private*/function _isLeaf($tag) {return in_array($tag, array('NAME', 'PASS', 'FAIL', 'EXCEPTION', 'MESSAGE', 'FORMATTED', 'SIGNAL'));}/*** Handler for start of event element.* @param resource $expat Parser handle.* @param string $tag Element name.* @param hash $attributes Name value pairs.* Attributes without content* are marked as true.* @access protected*/function _startElement($expat, $tag, $attributes) {$this->_attributes = $attributes;if ($tag == 'GROUP') {$this->_pushNestingTag(new NestingGroupTag($attributes));} elseif ($tag == 'CASE') {$this->_pushNestingTag(new NestingCaseTag($attributes));} elseif ($tag == 'TEST') {$this->_pushNestingTag(new NestingMethodTag($attributes));} elseif ($this->_isLeaf($tag)) {$this->_in_content_tag = true;$this->_content = '';}}/*** End of element event.* @param resource $expat Parser handle.* @param string $tag Element name.* @access protected*/function _endElement($expat, $tag) {$this->_in_content_tag = false;if (in_array($tag, array('GROUP', 'CASE', 'TEST'))) {$nesting_tag = $this->_popNestingTag();$nesting_tag->paintEnd($this->_listener);} elseif ($tag == 'NAME') {$nesting_tag = $this->_getCurrentNestingTag();$nesting_tag->setName($this->_content);$nesting_tag->paintStart($this->_listener);} elseif ($tag == 'PASS') {$this->_listener->paintPass($this->_content);} elseif ($tag == 'FAIL') {$this->_listener->paintFail($this->_content);} elseif ($tag == 'EXCEPTION') {$this->_listener->paintError($this->_content);} elseif ($tag == 'SIGNAL') {$this->_listener->paintSignal($this->_attributes['TYPE'],unserialize($this->_content));} elseif ($tag == 'MESSAGE') {$this->_listener->paintMessage($this->_content);} elseif ($tag == 'FORMATTED') {$this->_listener->paintFormattedMessage($this->_content);}}/*** Content between start and end elements.* @param resource $expat Parser handle.* @param string $text Usually output messages.* @access protected*/function _addContent($expat, $text) {if ($this->_in_content_tag) {$this->_content .= $text;}return true;}/*** XML and Doctype handler. Discards all such content.* @param resource $expat Parser handle.* @param string $default Text of default content.* @access protected*/function _default($expat, $default) {}}?>