diff options
Diffstat (limited to 'tests/test_tools/simpletest/page.php')
-rw-r--r-- | tests/test_tools/simpletest/page.php | 584 |
1 files changed, 299 insertions, 285 deletions
diff --git a/tests/test_tools/simpletest/page.php b/tests/test_tools/simpletest/page.php index 843dedf5..a7dc3a78 100644 --- a/tests/test_tools/simpletest/page.php +++ b/tests/test_tools/simpletest/page.php @@ -3,7 +3,7 @@ * Base include file for SimpleTest * @package SimpleTest * @subpackage WebTester - * @version $Id: page.php,v 1.105 2005/02/04 05:32:16 lastcraft Exp $ + * @version $Id: page.php,v 1.131 2006/02/05 01:07:49 lastcraft Exp $ */ /**#@+ @@ -13,8 +13,103 @@ require_once(dirname(__FILE__) . '/parser.php'); require_once(dirname(__FILE__) . '/tag.php'); require_once(dirname(__FILE__) . '/form.php'); + require_once(dirname(__FILE__) . '/selector.php'); /**#@-*/ - + + /** + * Creates tags and widgets given HTML tag + * attributes. + * @package SimpleTest + * @subpackage WebTester + */ + class SimpleTagBuilder { + + /** + * Factory for the tag objects. Creates the + * appropriate tag object for the incoming tag name + * and attributes. + * @param string $name HTML tag name. + * @param hash $attributes Element attributes. + * @return SimpleTag Tag object. + * @access public + */ + function createTag($name, $attributes) { + static $map = array( + 'a' => 'SimpleAnchorTag', + 'title' => 'SimpleTitleTag', + 'button' => 'SimpleButtonTag', + 'textarea' => 'SimpleTextAreaTag', + 'option' => 'SimpleOptionTag', + 'label' => 'SimpleLabelTag', + 'form' => 'SimpleFormTag', + 'frame' => 'SimpleFrameTag'); + $attributes = $this->_keysToLowerCase($attributes); + if (array_key_exists($name, $map)) { + $tag_class = $map[$name]; + return new $tag_class($attributes); + } elseif ($name == 'select') { + return $this->_createSelectionTag($attributes); + } elseif ($name == 'input') { + return $this->_createInputTag($attributes); + } + return new SimpleTag($name, $attributes); + } + + /** + * Factory for selection fields. + * @param hash $attributes Element attributes. + * @return SimpleTag Tag object. + * @access protected + */ + function _createSelectionTag($attributes) { + if (isset($attributes['multiple'])) { + return new MultipleSelectionTag($attributes); + } + return new SimpleSelectionTag($attributes); + } + + /** + * Factory for input tags. + * @param hash $attributes Element attributes. + * @return SimpleTag Tag object. + * @access protected + */ + function _createInputTag($attributes) { + if (! isset($attributes['type'])) { + return new SimpleTextTag($attributes); + } + $type = strtolower(trim($attributes['type'])); + $map = array( + 'submit' => 'SimpleSubmitTag', + 'image' => 'SimpleImageSubmitTag', + 'checkbox' => 'SimpleCheckboxTag', + 'radio' => 'SimpleRadioButtonTag', + 'text' => 'SimpleTextTag', + 'hidden' => 'SimpleTextTag', + 'password' => 'SimpleTextTag', + 'file' => 'SimpleUploadTag'); + if (array_key_exists($type, $map)) { + $tag_class = $map[$type]; + return new $tag_class($attributes); + } + return false; + } + + /** + * Make the keys lower case for case insensitive look-ups. + * @param hash $map Hash to convert. + * @return hash Unchanged values, but keys lower case. + * @access private + */ + function _keysToLowerCase($map) { + $lower = array(); + foreach ($map as $key => $value) { + $lower[strtolower($key)] = $value; + } + return $lower; + } + } + /** * SAX event handler. Maintains a list of * open tags and dispatches them as they close. @@ -24,7 +119,8 @@ class SimplePageBuilder extends SimpleSaxListener { protected $_tags; protected $_page; - + protected $_private_content_tag; + /** * Sets the builder up empty. * @access public @@ -34,13 +130,24 @@ } /** + * Frees up any references so as to allow the PHP garbage + * collection from unset() to work. + * @access public + */ + function free() { + unset($this->_tags); + unset($this->_page); + unset($this->_private_content_tags); + } + + /** * Reads the raw content and send events * into the page to be built. * @param $response SimpleHttpResponse Fetched response. * @return SimplePage Newly parsed page. * @access public */ - function parse($response) { + function &parse($response) { $this->_tags = array(); $this->_page = $this->_createPage($response); $parser = $this->_createParser($this); @@ -48,16 +155,17 @@ $this->_page->acceptPageEnd(); return $this->_page; } - + /** * Creates an empty page. * @return SimplePage New unparsed page. * @access protected */ - function _createPage($response) { - return new SimplePage($response); + function &_createPage($response) { + $page = new SimplePage($response); + return $page; } - + /** * Creates the parser used with the builder. * @param $listener SimpleSaxListener Target of parser. @@ -65,22 +173,9 @@ * events for the builder. * @access protected */ - function _createParser($listener) { - return new SimpleSaxParser($listener); - } - - /** - * Make the keys lower case for case insensitive look-ups. - * @param hash $map Hash to convert. - * @return hash Unchanged values, but keys lower case. - * @access private - */ - function _keysToLowerCase($map) { - $lower = array(); - foreach ($map as $key => $value) { - $lower[strtolower($key)] = $value; - } - return $lower; + function &_createParser($listener) { + $parser = new SimpleHtmlSaxParser($listener); + return $parser; } /** @@ -92,19 +187,31 @@ * @access public */ function startElement($name, $attributes) { - $tag = $this->_createTag($name, $this->_keysToLowerCase($attributes)); - if ($name == 'form') { + $factory = new SimpleTagBuilder(); + $tag = $factory->createTag($name, $attributes); + if (! $tag) { + return true; + } + if ($tag->getTagName() == 'label') { + $this->_page->acceptLabelStart($tag); + $this->_openTag($tag); + return true; + } + if ($tag->getTagName() == 'form') { $this->_page->acceptFormStart($tag); return true; - } - if ($name == 'frameset') { + } + if ($tag->getTagName() == 'frameset') { $this->_page->acceptFramesetStart($tag); return true; - } - if ($name == 'frame') { + } + if ($tag->getTagName() == 'frame') { $this->_page->acceptFrame($tag); return true; - } + } + if ($tag->isPrivateContent() && ! isset($this->_private_content_tag)) { + $this->_private_content_tag = $tag; + } if ($tag->expectEndTag()) { $this->_openTag($tag); return true; @@ -112,7 +219,7 @@ $this->_page->acceptTag($tag); return true; } - + /** * End of element event. * @param string $name Element name. @@ -120,23 +227,41 @@ * @access public */ function endElement($name) { + if ($name == 'label') { + $this->_page->acceptLabelEnd(); + return true; + } if ($name == 'form') { $this->_page->acceptFormEnd(); return true; - } + } if ($name == 'frameset') { $this->_page->acceptFramesetEnd(); return true; - } - if (isset($this->_tags[$name]) && (count($this->_tags[$name]) > 0)) { + } + if ($this->_hasNamedTagOnOpenTagStack($name)) { $tag = array_pop($this->_tags[$name]); + if ($tag->isPrivateContent() && $this->_private_content_tag->getTagName() == $name) { + unset($this->_private_content_tag); + } $this->_addContentTagToOpenTags($tag); $this->_page->acceptTag($tag); return true; } return true; } - + + /** + * Test to see if there are any open tags awaiting + * closure that match the tag name. + * @param string $name Element name. + * @return boolean True if any are still open. + * @access private + */ + function _hasNamedTagOnOpenTagStack($name) { + return isset($this->_tags[$name]) && (count($this->_tags[$name]) > 0); + } + /** * Unparsed, but relevant data. The data is added * to every open tag. @@ -145,18 +270,33 @@ * @access public */ function addContent($text) { + if (isset($this->_private_content_tag)) { + $this->_private_content_tag->addContent($text); + } else { + $this->_addContentToAllOpenTags($text); + } + return true; + } + + /** + * Any content fills all currently open tags unless it + * is part of an option tag. + * @param string $text May include unparsed tags. + * @access private + */ + function _addContentToAllOpenTags($text) { foreach (array_keys($this->_tags) as $name) { for ($i = 0, $count = count($this->_tags[$name]); $i < $count; $i++) { $this->_tags[$name][$i]->addContent($text); } } - return true; } - + /** - * Parsed relevant data. The parsed tag is added - * to every open tag. - * @param SimpleTag $tag May include unparsed tags. + * Parsed data in tag form. The parsed tag is added + * to every open tag. Used for adding options to select + * fields only. + * @param SimpleTag $tag Option tags only. * @access private */ function _addContentTagToOpenTags($tag) { @@ -169,7 +309,7 @@ } } } - + /** * Opens a tag for receiving content. Multiple tags * will be receiving input at the same time. @@ -181,78 +321,10 @@ if (! in_array($name, array_keys($this->_tags))) { $this->_tags[$name] = array(); } - array_push($this->_tags[$name], $tag); - } - - /** - * Factory for the tag objects. Creates the - * appropriate tag object for the incoming tag name. - * @param string $name HTML tag name. - * @param hash $attributes Element attributes. - * @return SimpleTag Tag object. - * @access protected - */ - function _createTag($name, $attributes) { - if ($name == 'a') { - return new SimpleAnchorTag($attributes); - } elseif ($name == 'title') { - return new SimpleTitleTag($attributes); - } elseif ($name == 'input') { - return $this->_createInputTag($attributes); - } elseif ($name == 'button') { - return new SimpleButtonTag($attributes); - } elseif ($name == 'textarea') { - return new SimpleTextAreaTag($attributes); - } elseif ($name == 'select') { - return $this->_createSelectionTag($attributes); - } elseif ($name == 'option') { - return new SimpleOptionTag($attributes); - } elseif ($name == 'form') { - return new SimpleFormTag($attributes); - } elseif ($name == 'frame') { - return new SimpleFrameTag($attributes); - } - return new SimpleTag($name, $attributes); - } - - /** - * Factory for selection fields. - * @param hash $attributes Element attributes. - * @return SimpleTag Tag object. - * @access protected - */ - function _createSelectionTag($attributes) { - if (isset($attributes['multiple'])) { - return new MultipleSelectionTag($attributes); - } - return new SimpleSelectionTag($attributes); - } - - /** - * Factory for input tags. - * @param hash $attributes Element attributes. - * @return SimpleTag Tag object. - * @access protected - */ - function _createInputTag($attributes) { - if (! isset($attributes['type'])) { - return new SimpleTextTag($attributes); - } - $type = strtolower($attributes['type']); - if ($type == 'submit') { - return new SimpleSubmitTag($attributes); - } elseif ($type == 'image') { - return new SimpleImageSubmitTag($attributes); - } elseif ($type == 'checkbox') { - return new SimpleCheckboxTag($attributes); - } elseif ($type == 'radio') { - return new SimpleRadioButtonTag($attributes); - } else { - return new SimpleTextTag($attributes); - } + $this->_tags[$name][] = $tag; } } - + /** * A wrapper for a web page. * @package SimpleTest @@ -261,6 +333,9 @@ class SimplePage { protected $_links; protected $_title; + protected $_last_widget; + protected $_label; + protected $_left_over_labels; protected $_open_forms; protected $_complete_forms; protected $_frameset; @@ -274,7 +349,7 @@ protected $_method; protected $_url; protected $_request_data; - + /** * Parses a page ready to access it's contents. * @param SimpleHttpResponse $response Result of HTTP fetch. @@ -283,6 +358,7 @@ function SimplePage($response = false) { $this->_links = array(); $this->_title = false; + $this->_left_over_labels = array(); $this->_open_forms = array(); $this->_complete_forms = array(); $this->_frameset = false; @@ -295,7 +371,7 @@ $this->_noResponse(); } } - + /** * Extracts all of the response information. * @param SimpleHttpResponse $response Response being parsed. @@ -310,7 +386,7 @@ $this->_url = $response->getUrl(); $this->_request_data = $response->getRequestData(); } - + /** * Sets up a missing response. * @access private @@ -324,7 +400,7 @@ $this->_url = false; $this->_request_data = false; } - + /** * Original request as bytes sent down the wire. * @return mixed Sent content. @@ -333,7 +409,7 @@ function getRequest() { return $this->_sent; } - + /** * Accessor for raw text of page. * @return string Raw unparsed content. @@ -342,7 +418,7 @@ function getRaw() { return $this->_raw; } - + /** * Accessor for plain text of page as a text browser * would see it. @@ -351,11 +427,11 @@ */ function getText() { if (! $this->_text) { - $this->_text = SimpleSaxParser::normalise($this->_raw); + $this->_text = SimpleHtmlSaxParser::normalise($this->_raw); } return $this->_text; } - + /** * Accessor for raw headers of page. * @return string Header block as text. @@ -367,7 +443,7 @@ } return false; } - + /** * Original request method. * @return string GET, POST or HEAD. @@ -376,7 +452,7 @@ function getMethod() { return $this->_method; } - + /** * Original resource name. * @return SimpleUrl Current url. @@ -385,7 +461,7 @@ function getUrl() { return $this->_url; } - + /** * Original request data. * @return mixed Sent content. @@ -394,7 +470,7 @@ function getRequestData() { return $this->_request_data; } - + /** * Accessor for last error. * @return string Error from last response. @@ -403,7 +479,7 @@ function getTransportError() { return $this->_transport_error; } - + /** * Accessor for current MIME type. * @return string MIME type as string; e.g. 'text/html' @@ -415,7 +491,7 @@ } return false; } - + /** * Accessor for HTTP response code. * @return integer HTTP response code received. @@ -427,7 +503,7 @@ } return false; } - + /** * Accessor for last Authentication type. Only valid * straight after a challenge (401). @@ -440,7 +516,7 @@ } return false; } - + /** * Accessor for last Authentication realm. Only valid * straight after a challenge (401). @@ -453,7 +529,7 @@ } return false; } - + /** * Accessor for current frame focus. Will be * false as no frames. @@ -463,7 +539,7 @@ function getFrameFocus() { return array(); } - + /** * Sets the focus by index. The integer index starts from 1. * @param integer $choice Chosen frame. @@ -473,7 +549,7 @@ function setFrameFocusByIndex($choice) { return false; } - + /** * Sets the focus by name. Always fails for a leaf page. * @param string $name Chosen frame. @@ -483,14 +559,14 @@ function setFrameFocus($name) { return false; } - + /** * Clears the frame focus. Does nothing for a leaf page. * @access public */ function clearFrameFocus() { } - + /** * Adds a tag to the page. * @param SimpleTag $tag Tag to accept. @@ -505,9 +581,36 @@ for ($i = 0; $i < count($this->_open_forms); $i++) { $this->_open_forms[$i]->addWidget($tag); } + $this->_last_widget = $tag; } } - + + /** + * Opens a label for a described widget. + * @param SimpleFormTag $tag Tag to accept. + * @access public + */ + function acceptLabelStart($tag) { + $this->_label = $tag; + unset($this->_last_widget); + } + + /** + * Closes the most recently opened label. + * @access public + */ + function acceptLabelEnd() { + if (isset($this->_label)) { + if (isset($this->_last_widget)) { + $this->_last_widget->setLabel($this->_label->getText()); + unset($this->_last_widget); + } else { + $this->_left_over_labels[] = SimpleTestCompatibility::copy($this->_label); + } + unset($this->_label); + } + } + /** * Tests to see if a tag is a possible form * element. @@ -518,7 +621,7 @@ function _isFormElement($name) { return in_array($name, array('input', 'button', 'textarea', 'select')); } - + /** * Opens a form. New widgets go here. * @param SimpleFormTag $tag Tag to accept. @@ -527,7 +630,7 @@ function acceptFormStart($tag) { $this->_open_forms[] = new SimpleForm($tag, $this->getUrl()); } - + /** * Closes the most recently opened form. * @access public @@ -537,7 +640,7 @@ $this->_complete_forms[] = array_pop($this->_open_forms); } } - + /** * Opens a frameset. A frameset may contain nested * frameset tags. @@ -550,7 +653,7 @@ } $this->_frameset_nesting_level++; } - + /** * Closes the most recently opened frameset. * @access public @@ -560,7 +663,7 @@ $this->_frameset_nesting_level--; } } - + /** * Takes a single frame tag and stashes it in * the current frame set. @@ -574,7 +677,7 @@ } } } - + /** * Test to see if in the middle of reading * a frameset. @@ -587,7 +690,7 @@ } return ($this->_frameset_nesting_level > 0); } - + /** * Test to see if link is an absolute one. * @param string $url Url to test. @@ -598,7 +701,7 @@ $parsed = new SimpleUrl($url); return (boolean)($parsed->getScheme() && $parsed->getHost()); } - + /** * Adds a link to the page. * @param SimpleAnchorTag $tag Link to accept. @@ -607,7 +710,7 @@ function _addLink($tag) { $this->_links[] = $tag; } - + /** * Marker for end of complete page. Any work in * progress can now be closed. @@ -617,8 +720,15 @@ while (count($this->_open_forms)) { $this->_complete_forms[] = array_pop($this->_open_forms); } + foreach ($this->_left_over_labels as $label) { + for ($i = 0, $count = count($this->_complete_forms); $i < $count; $i++) { + $this->_complete_forms[$i]->attachLabelBySelector( + new SimpleById($label->getFor()), + $label->getText()); + } + } } - + /** * Test for the presence of a frameset. * @return boolean True if frameset. @@ -627,7 +737,7 @@ function hasFrames() { return (boolean)$this->_frameset; } - + /** * Accessor for frame name and source URL for every frame that * will need to be loaded. Immediate children only. @@ -649,7 +759,7 @@ } return $urls; } - + /** * Fetches a list of loaded frames. * @return array/string Just the URL for a single page. @@ -659,7 +769,7 @@ $url = $this->getUrl(); return $url->asString(); } - + /** * Accessor for a list of all fixed links. * @return array List of urls with scheme of @@ -675,7 +785,7 @@ } return $all; } - + /** * Accessor for a list of all relative links. * @return array List of urls without hostname. @@ -690,7 +800,7 @@ } return $all; } - + /** * Accessor for URLs by the link label. Label will match * regardess of whitespace issues and case. @@ -707,7 +817,7 @@ } return $matches; } - + /** * Accessor for a URL by the id attribute. * @param string $id Id attribute of link. @@ -722,7 +832,7 @@ } return false; } - + /** * Converts a link into a target URL. * @param SimpleAnchor $link Parsed link. @@ -736,7 +846,7 @@ } return $url; } - + /** * Expands expandomatic URLs into fully qualified * URLs. @@ -750,7 +860,7 @@ } return $url->makeAbsolute($this->getUrl()); } - + /** * Sets the title tag contents. * @param SimpleTitleTag $tag Title of page. @@ -759,7 +869,7 @@ function _setTitle($tag) { $this->_title = $tag; } - + /** * Accessor for parsed title. * @return string Title or false if no title is present. @@ -771,103 +881,43 @@ } return false; } - - /** - * Finds a held form by button label. Will only - * search correctly built forms. - * @param string $label Button label, default 'Submit'. - * @return SimpleForm Form object containing the button. - * @access public - */ - function getFormBySubmitLabel($label) { - for ($i = 0; $i < count($this->_complete_forms); $i++) { - if ($this->_complete_forms[$i]->hasSubmitLabel($label)) { - return $this->_complete_forms[$i]; - } - } - return null; - } - + /** * Finds a held form by button label. Will only * search correctly built forms. - * @param string $name Button name attribute. - * @return SimpleForm Form object containing the button. - * @access public - */ - function getFormBySubmitName($name) { - for ($i = 0; $i < count($this->_complete_forms); $i++) { - if ($this->_complete_forms[$i]->hasSubmitName($name)) { - return $this->_complete_forms[$i]; - } - } - return null; - } - - /** - * Finds a held form by button id. Will only - * search correctly built forms. - * @param string $id Button ID attribute. - * @return SimpleForm Form object containing the button. + * @param SimpleSelector $selector Button finder. + * @return SimpleForm Form object containing + * the button. * @access public */ - function getFormBySubmitId($id) { + function &getFormBySubmit($selector) { for ($i = 0; $i < count($this->_complete_forms); $i++) { - if ($this->_complete_forms[$i]->hasSubmitId($id)) { + if ($this->_complete_forms[$i]->hasSubmit($selector)) { return $this->_complete_forms[$i]; } } - return null; + $null = null; + return $null; } - - /** - * Finds a held form by image label. Will only - * search correctly built forms. - * @param string $label Usually the alt attribute. - * @return SimpleForm Form object containing the image. - * @access public - */ - function getFormByImageLabel($label) { - for ($i = 0; $i < count($this->_complete_forms); $i++) { - if ($this->_complete_forms[$i]->hasImageLabel($label)) { - return $this->_complete_forms[$i]; - } - } - return null; - } - - /** - * Finds a held form by image button id. Will only - * search correctly built forms. - * @param string $name Image name. - * @return SimpleForm Form object containing the image. - * @access public - */ - function getFormByImageName($name) { - for ($i = 0; $i < count($this->_complete_forms); $i++) { - if ($this->_complete_forms[$i]->hasImageName($name)) { - return $this->_complete_forms[$i]; - } - } - return null; - } - + /** - * Finds a held form by image button id. Will only - * search correctly built forms. - * @param string $id Image ID attribute. - * @return SimpleForm Form object containing the image. + * Finds a held form by image using a selector. + * Will only search correctly built forms. + * @param SimpleSelector $selector Image finder. + * @return SimpleForm Form object containing + * the image. * @access public */ - function getFormByImageId($id) { + function &getFormByImage($selector) { for ($i = 0; $i < count($this->_complete_forms); $i++) { - if ($this->_complete_forms[$i]->hasImageId($id)) { + if ($this->_complete_forms[$i]->hasImage($selector)) { return $this->_complete_forms[$i]; } } - return null; + $null = null; + return $null; } - + /** * Finds a held form by the form ID. A way of * identifying a specific form when we have control @@ -876,81 +926,45 @@ * @return SimpleForm Form object containing the matching ID. * @access public */ - function getFormById($id) { + function &getFormById($id) { for ($i = 0; $i < count($this->_complete_forms); $i++) { if ($this->_complete_forms[$i]->getId() == $id) { return $this->_complete_forms[$i]; } } - return null; + $null = null; + return $null; } - + /** * Sets a field on each form in which the field is * available. - * @param string $name Field name. - * @param string $value Value to set field to. - * @return boolean True if value is valid. + * @param SimpleSelector $selector Field finder. + * @param string $value Value to set field to. + * @return boolean True if value is valid. * @access public */ - function setField($name, $value) { + function setField($selector, $value) { $is_set = false; for ($i = 0; $i < count($this->_complete_forms); $i++) { - if ($this->_complete_forms[$i]->setField($name, $value)) { + if ($this->_complete_forms[$i]->setField($selector, $value)) { $is_set = true; } } return $is_set; } - - /** - * Sets a field on the form in which the unique field is - * available. - * @param string/integer $id Field ID attribute. - * @param string $value Value to set field to. - * @return boolean True if value is valid. - * @access public - */ - function setFieldById($id, $value) { - for ($i = 0; $i < count($this->_complete_forms); $i++) { - if ($this->_complete_forms[$i]->setFieldById($id, $value)) { - return true; - } - } - return false; - } - - /** - * Accessor for a form element value within a page. - * Finds the first match. - * @param string $name Field name. - * @return string/boolean A string if the field is - * present, false if unchecked - * and null if missing. - * @access public - */ - function getField($name) { - for ($i = 0; $i < count($this->_complete_forms); $i++) { - $value = $this->_complete_forms[$i]->getValue($name); - if (isset($value)) { - return $value; - } - } - return null; - } - + /** * Accessor for a form element value within a page. - * Finds the first match. - * @param string/integer $id Field ID attribute. - * @return string/boolean A string if the field is - * present, false if unchecked - * and null if missing. + * @param SimpleSelector $selector Field finder. + * @return string/boolean A string if the field is + * present, false if unchecked + * and null if missing. * @access public */ - function getFieldById($id) { + function getField($selector) { for ($i = 0; $i < count($this->_complete_forms); $i++) { - $value = $this->_complete_forms[$i]->getValueById($id); + $value = $this->_complete_forms[$i]->getValue($selector); if (isset($value)) { return $value; } |