Source for file tag.php

Documentation is available at tag.php

  1. <?php
  2. /**
  3.  *  Base include file for SimpleTest.
  4.  *  @package    SimpleTest
  5.  *  @subpackage WebTester
  6.  *  @version    $Id: tag.php 1929 2009-07-31 13:49:36Z dgheath $
  7.  */
  8.  
  9. /**#@+
  10.  * include SimpleTest files
  11.  */
  12. require_once(dirname(__FILE__'/page.php');
  13. require_once(dirname(__FILE__'/encoding.php');
  14. /**#@-*/
  15.  
  16. /**
  17.  *    Creates tags and widgets given HTML tag
  18.  *    attributes.
  19.  *    @package SimpleTest
  20.  *    @subpackage WebTester
  21.  */
  22.  
  23.     /**
  24.      *    Factory for the tag objects. Creates the
  25.      *    appropriate tag object for the incoming tag name
  26.      *    and attributes.
  27.      *    @param string $name        HTML tag name.
  28.      *    @param hash $attributes    Element attributes.
  29.      *    @return SimpleTag          Tag object.
  30.      *    @access public
  31.      */
  32.     function createTag($name$attributes{
  33.         static $map array(
  34.                 'a' => 'SimpleAnchorTag',
  35.                 'title' => 'SimpleTitleTag',
  36.                 'base' => 'SimpleBaseTag',
  37.                 'button' => 'SimpleButtonTag',
  38.                 'textarea' => 'SimpleTextAreaTag',
  39.                 'option' => 'SimpleOptionTag',
  40.                 'label' => 'SimpleLabelTag',
  41.                 'form' => 'SimpleFormTag',
  42.                 'frame' => 'SimpleFrameTag');
  43.         $attributes $this->keysToLowerCase($attributes);
  44.         if (array_key_exists($name$map)) {
  45.             $tag_class $map[$name];
  46.             return new $tag_class($attributes);
  47.         elseif ($name == 'select'{
  48.             return $this->createSelectionTag($attributes);
  49.         elseif ($name == 'input'{
  50.             return $this->createInputTag($attributes);
  51.         }
  52.         return new SimpleTag($name$attributes);
  53.     }
  54.  
  55.     /**
  56.      *    Factory for selection fields.
  57.      *    @param hash $attributes    Element attributes.
  58.      *    @return SimpleTag          Tag object.
  59.      *    @access protected
  60.      */
  61.     protected function createSelectionTag($attributes{
  62.         if (isset($attributes['multiple'])) {
  63.             return new MultipleSelectionTag($attributes);
  64.         }
  65.         return new SimpleSelectionTag($attributes);
  66.     }
  67.  
  68.     /**
  69.      *    Factory for input tags.
  70.      *    @param hash $attributes    Element attributes.
  71.      *    @return SimpleTag          Tag object.
  72.      *    @access protected
  73.      */
  74.     protected function createInputTag($attributes{
  75.         if (isset($attributes['type'])) {
  76.             return new SimpleTextTag($attributes);
  77.         }
  78.         $type strtolower(trim($attributes['type']));
  79.         $map array(
  80.                 'submit' => 'SimpleSubmitTag',
  81.                 'image' => 'SimpleImageSubmitTag',
  82.                 'checkbox' => 'SimpleCheckboxTag',
  83.                 'radio' => 'SimpleRadioButtonTag',
  84.                 'text' => 'SimpleTextTag',
  85.                 'hidden' => 'SimpleTextTag',
  86.                 'password' => 'SimpleTextTag',
  87.                 'file' => 'SimpleUploadTag');
  88.         if (array_key_exists($type$map)) {
  89.             $tag_class $map[$type];
  90.             return new $tag_class($attributes);
  91.         }
  92.         return false;
  93.     }
  94.  
  95.     /**
  96.      *    Make the keys lower case for case insensitive look-ups.
  97.      *    @param hash $map   Hash to convert.
  98.      *    @return hash       Unchanged values, but keys lower case.
  99.      *    @access private
  100.      */
  101.     protected function keysToLowerCase($map{
  102.         $lower array();
  103.         foreach ($map as $key => $value{
  104.             $lower[strtolower($key)$value;
  105.         }
  106.         return $lower;
  107.     }
  108. }
  109.  
  110. /**
  111.  *    HTML or XML tag.
  112.  *    @package SimpleTest
  113.  *    @subpackage WebTester
  114.  */
  115. class SimpleTag {
  116.     private $name;
  117.     private $attributes;
  118.     private $content;
  119.  
  120.     /**
  121.      *    Starts with a named tag with attributes only.
  122.      *    @param string $name        Tag name.
  123.      *    @param hash $attributes    Attribute names and
  124.      *                                string values. Note that
  125.      *                                the keys must have been
  126.      *                                converted to lower case.
  127.      */
  128.     function __construct($name$attributes{
  129.         $this->name strtolower(trim($name));
  130.         $this->attributes $attributes;
  131.         $this->content '';
  132.     }
  133.  
  134.     /**
  135.      *    Check to see if the tag can have both start and
  136.      *    end tags with content in between.
  137.      *    @return boolean        True if content allowed.
  138.      *    @access public
  139.      */
  140.     function expectEndTag({
  141.         return true;
  142.     }
  143.  
  144.     /**
  145.      *    The current tag should not swallow all content for
  146.      *    itself as it's searchable page content. Private
  147.      *    content tags are usually widgets that contain default
  148.      *    values.
  149.      *    @return boolean        False as content is available
  150.      *                            to other tags by default.
  151.      *    @access public
  152.      */
  153.     function isPrivateContent({
  154.         return false;
  155.     }
  156.  
  157.     /**
  158.      *    Appends string content to the current content.
  159.      *    @param string $content        Additional text.
  160.      *    @access public
  161.      */
  162.     function addContent($content{
  163.         $this->content .= (string)$content;
  164.         return $this;
  165.     }
  166.  
  167.     /**
  168.      *    Adds an enclosed tag to the content.
  169.      *    @param SimpleTag $tag    New tag.
  170.      *    @access public
  171.      */
  172.     function addTag($tag{
  173.     }
  174.  
  175.     /**
  176.      *    Adds multiple enclosed tags to the content.
  177.      *    @param array            List of SimpleTag objects to be added.
  178.      */
  179.     function addTags($tags{
  180.         foreach ($tags as $tag{
  181.             $this->addTag($tag);
  182.         }
  183.     }
  184.     
  185.     /**
  186.      *    Accessor for tag name.
  187.      *    @return string       Name of tag.
  188.      *    @access public
  189.      */
  190.     function getTagName({
  191.         return $this->name;
  192.     }
  193.  
  194.     /**
  195.      *    List of legal child elements.
  196.      *    @return array        List of element names.
  197.      *    @access public
  198.      */
  199.     function getChildElements({
  200.         return array();
  201.     }
  202.  
  203.     /**
  204.      *    Accessor for an attribute.
  205.      *    @param string $label    Attribute name.
  206.      *    @return string          Attribute value.
  207.      *    @access public
  208.      */
  209.     function getAttribute($label{
  210.         $label strtolower($label);
  211.         if (isset($this->attributes[$label])) {
  212.             return false;
  213.         }
  214.         return (string)$this->attributes[$label];
  215.     }
  216.  
  217.     /**
  218.      *    Sets an attribute.
  219.      *    @param string $label    Attribute name.
  220.      *    @return string $value   New attribute value.
  221.      *    @access protected
  222.      */
  223.     protected function setAttribute($label$value{
  224.         $this->attributes[strtolower($label)$value;
  225.     }
  226.  
  227.     /**
  228.      *    Accessor for the whole content so far.
  229.      *    @return string       Content as big raw string.
  230.      *    @access public
  231.      */
  232.     function getContent({
  233.         return $this->content;
  234.     }
  235.  
  236.     /**
  237.      *    Accessor for content reduced to visible text. Acts
  238.      *    like a text mode browser, normalising space and
  239.      *    reducing images to their alt text.
  240.      *    @return string       Content as plain text.
  241.      *    @access public
  242.      */
  243.     function getText({
  244.         return SimplePage::normalise($this->content);
  245.     }
  246.  
  247.     /**
  248.      *    Test to see if id attribute matches.
  249.      *    @param string $id        ID to test against.
  250.      *    @return boolean          True on match.
  251.      *    @access public
  252.      */
  253.     function isId($id{
  254.         return ($this->getAttribute('id'== $id);
  255.     }
  256. }
  257.  
  258. /**
  259.  *    Base url.
  260.  *    @package SimpleTest
  261.  *    @subpackage WebTester
  262.  */
  263. class SimpleBaseTag extends SimpleTag {
  264.  
  265.     /**
  266.      *    Starts with a named tag with attributes only.
  267.      *    @param hash $attributes    Attribute names and
  268.      *                                string values.
  269.      */
  270.     function __construct($attributes{
  271.         parent::__construct('base'$attributes);
  272.     }
  273.  
  274.     /**
  275.      *    Base tag is not a block tag.
  276.      *    @return boolean       false
  277.      *    @access public
  278.      */
  279.     function expectEndTag({
  280.         return false;
  281.     }
  282. }
  283.  
  284. /**
  285.  *    Page title.
  286.  *    @package SimpleTest
  287.  *    @subpackage WebTester
  288.  */
  289. class SimpleTitleTag extends SimpleTag {
  290.  
  291.     /**
  292.      *    Starts with a named tag with attributes only.
  293.      *    @param hash $attributes    Attribute names and
  294.      *                                string values.
  295.      */
  296.     function __construct($attributes{
  297.         parent::__construct('title'$attributes);
  298.     }
  299. }
  300.  
  301. /**
  302.  *    Link.
  303.  *    @package SimpleTest
  304.  *    @subpackage WebTester
  305.  */
  306. class SimpleAnchorTag extends SimpleTag {
  307.  
  308.     /**
  309.      *    Starts with a named tag with attributes only.
  310.      *    @param hash $attributes    Attribute names and
  311.      *                                string values.
  312.      */
  313.     function __construct($attributes{
  314.         parent::__construct('a'$attributes);
  315.     }
  316.  
  317.     /**
  318.      *    Accessor for URL as string.
  319.      *    @return string    Coerced as string.
  320.      *    @access public
  321.      */
  322.     function getHref({
  323.         $url $this->getAttribute('href');
  324.         if (is_bool($url)) {
  325.             $url '';
  326.         }
  327.         return $url;
  328.     }
  329. }
  330.  
  331. /**
  332.  *    Form element.
  333.  *    @package SimpleTest
  334.  *    @subpackage WebTester
  335.  */
  336. class SimpleWidget extends SimpleTag {
  337.     private $value;
  338.     private $label;
  339.     private $is_set;
  340.  
  341.     /**
  342.      *    Starts with a named tag with attributes only.
  343.      *    @param string $name        Tag name.
  344.      *    @param hash $attributes    Attribute names and
  345.      *                                string values.
  346.      */
  347.     function __construct($name$attributes{
  348.         parent::__construct($name$attributes);
  349.         $this->value false;
  350.         $this->label false;
  351.         $this->is_set false;
  352.     }
  353.  
  354.     /**
  355.      *    Accessor for name submitted as the key in
  356.      *    GET/POST privateiables hash.
  357.      *    @return string        Parsed value.
  358.      *    @access public
  359.      */
  360.     function getName({
  361.         return $this->getAttribute('name');
  362.     }
  363.  
  364.     /**
  365.      *    Accessor for default value parsed with the tag.
  366.      *    @return string        Parsed value.
  367.      *    @access public
  368.      */
  369.     function getDefault({
  370.         return $this->getAttribute('value');
  371.     }
  372.  
  373.     /**
  374.      *    Accessor for currently set value or default if
  375.      *    none.
  376.      *    @return string      Value set by form or default
  377.      *                         if none.
  378.      *    @access public
  379.      */
  380.     function getValue({
  381.         if ($this->is_set{
  382.             return $this->getDefault();
  383.         }
  384.         return $this->value;
  385.     }
  386.  
  387.     /**
  388.      *    Sets the current form element value.
  389.      *    @param string $value       New value.
  390.      *    @return boolean            True if allowed.
  391.      *    @access public
  392.      */
  393.     function setValue($value{
  394.         $this->value $value;
  395.         $this->is_set true;
  396.         return true;
  397.     }
  398.  
  399.     /**
  400.      *    Resets the form element value back to the
  401.      *    default.
  402.      *    @access public
  403.      */
  404.     function resetValue({
  405.         $this->is_set false;
  406.     }
  407.  
  408.     /**
  409.      *    Allows setting of a label externally, say by a
  410.      *    label tag.
  411.      *    @param string $label    Label to attach.
  412.      *    @access public
  413.      */
  414.     function setLabel($label{
  415.         $this->label trim($label);
  416.         return $this;
  417.     }
  418.  
  419.     /**
  420.      *    Reads external or internal label.
  421.      *    @param string $label    Label to test.
  422.      *    @return boolean         True is match.
  423.      *    @access public
  424.      */
  425.     function isLabel($label{
  426.         return $this->label == trim($label);
  427.     }
  428.  
  429.     /**
  430.      *    Dispatches the value into the form encoded packet.
  431.      *    @param SimpleEncoding $encoding    Form packet.
  432.      *    @access public
  433.      */
  434.     function write($encoding{
  435.         if ($this->getName()) {
  436.             $encoding->add($this->getName()$this->getValue());
  437.         }
  438.     }
  439. }
  440.  
  441. /**
  442.  *    Text, password and hidden field.
  443.  *    @package SimpleTest
  444.  *    @subpackage WebTester
  445.  */
  446. class SimpleTextTag extends SimpleWidget {
  447.  
  448.     /**
  449.      *    Starts with a named tag with attributes only.
  450.      *    @param hash $attributes    Attribute names and
  451.      *                                string values.
  452.      */
  453.     function __construct($attributes{
  454.         parent::__construct('input'$attributes);
  455.         if ($this->getAttribute('value'=== false{
  456.             $this->setAttribute('value''');
  457.         }
  458.     }
  459.  
  460.     /**
  461.      *    Tag contains no content.
  462.      *    @return boolean        False.
  463.      *    @access public
  464.      */
  465.     function expectEndTag({
  466.         return false;
  467.     }
  468.  
  469.     /**
  470.      *    Sets the current form element value. Cannot
  471.      *    change the value of a hidden field.
  472.      *    @param string $value       New value.
  473.      *    @return boolean            True if allowed.
  474.      *    @access public
  475.      */
  476.     function setValue($value{
  477.         if ($this->getAttribute('type'== 'hidden'{
  478.             return false;
  479.         }
  480.         return parent::setValue($value);
  481.     }
  482. }
  483.  
  484. /**
  485.  *    Submit button as input tag.
  486.  *    @package SimpleTest
  487.  *    @subpackage WebTester
  488.  */
  489. class SimpleSubmitTag extends SimpleWidget {
  490.  
  491.     /**
  492.      *    Starts with a named tag with attributes only.
  493.      *    @param hash $attributes    Attribute names and
  494.      *                                string values.
  495.      */
  496.     function __construct($attributes{
  497.         parent::__construct('input'$attributes);
  498.         if ($this->getAttribute('value'=== false{
  499.             $this->setAttribute('value''Submit');
  500.         }
  501.     }
  502.  
  503.     /**
  504.      *    Tag contains no end element.
  505.      *    @return boolean        False.
  506.      *    @access public
  507.      */
  508.     function expectEndTag({
  509.         return false;
  510.     }
  511.  
  512.     /**
  513.      *    Disables the setting of the button value.
  514.      *    @param string $value       Ignored.
  515.      *    @return boolean            True if allowed.
  516.      *    @access public
  517.      */
  518.     function setValue($value{
  519.         return false;
  520.     }
  521.  
  522.     /**
  523.      *    Value of browser visible text.
  524.      *    @return string        Visible label.
  525.      *    @access public
  526.      */
  527.     function getLabel({
  528.         return $this->getValue();
  529.     }
  530.  
  531.     /**
  532.      *    Test for a label match when searching.
  533.      *    @param string $label     Label to test.
  534.      *    @return boolean          True on match.
  535.      *    @access public
  536.      */
  537.     function isLabel($label{
  538.         return trim($label== trim($this->getLabel());
  539.     }
  540. }
  541.  
  542. /**
  543.  *    Image button as input tag.
  544.  *    @package SimpleTest
  545.  *    @subpackage WebTester
  546.  */
  547.  
  548.     /**
  549.      *    Starts with a named tag with attributes only.
  550.      *    @param hash $attributes    Attribute names and
  551.      *                                string values.
  552.      */
  553.     function __construct($attributes{
  554.         parent::__construct('input'$attributes);
  555.     }
  556.  
  557.     /**
  558.      *    Tag contains no end element.
  559.      *    @return boolean        False.
  560.      *    @access public
  561.      */
  562.     function expectEndTag({
  563.         return false;
  564.     }
  565.  
  566.     /**
  567.      *    Disables the setting of the button value.
  568.      *    @param string $value       Ignored.
  569.      *    @return boolean            True if allowed.
  570.      *    @access public
  571.      */
  572.     function setValue($value{
  573.         return false;
  574.     }
  575.  
  576.     /**
  577.      *    Value of browser visible text.
  578.      *    @return string        Visible label.
  579.      *    @access public
  580.      */
  581.     function getLabel({
  582.         if ($this->getAttribute('title')) {
  583.             return $this->getAttribute('title');
  584.         }
  585.         return $this->getAttribute('alt');
  586.     }
  587.  
  588.     /**
  589.      *    Test for a label match when searching.
  590.      *    @param string $label     Label to test.
  591.      *    @return boolean          True on match.
  592.      *    @access public
  593.      */
  594.     function isLabel($label{
  595.         return trim($label== trim($this->getLabel());
  596.     }
  597.  
  598.     /**
  599.      *    Dispatches the value into the form encoded packet.
  600.      *    @param SimpleEncoding $encoding    Form packet.
  601.      *    @param integer $x                  X coordinate of click.
  602.      *    @param integer $y                  Y coordinate of click.
  603.      *    @access public
  604.      */
  605.     function write($encoding$x 1$y 1{
  606.         if ($this->getName()) {
  607.             $encoding->add($this->getName('.x'$x);
  608.             $encoding->add($this->getName('.y'$y);
  609.         else {
  610.             $encoding->add('x'$x);
  611.             $encoding->add('y'$y);
  612.         }
  613.     }
  614. }
  615.  
  616. /**
  617.  *    Submit button as button tag.
  618.  *    @package SimpleTest
  619.  *    @subpackage WebTester
  620.  */
  621. class SimpleButtonTag extends SimpleWidget {
  622.  
  623.     /**
  624.      *    Starts with a named tag with attributes only.
  625.      *    Defaults are very browser dependent.
  626.      *    @param hash $attributes    Attribute names and
  627.      *                                string values.
  628.      */
  629.     function __construct($attributes{
  630.         parent::__construct('button'$attributes);
  631.     }
  632.  
  633.     /**
  634.      *    Check to see if the tag can have both start and
  635.      *    end tags with content in between.
  636.      *    @return boolean        True if content allowed.
  637.      *    @access public
  638.      */
  639.     function expectEndTag({
  640.         return true;
  641.     }
  642.  
  643.     /**
  644.      *    Disables the setting of the button value.
  645.      *    @param string $value       Ignored.
  646.      *    @return boolean            True if allowed.
  647.      *    @access public
  648.      */
  649.     function setValue($value{
  650.         return false;
  651.     }
  652.  
  653.     /**
  654.      *    Value of browser visible text.
  655.      *    @return string        Visible label.
  656.      *    @access public
  657.      */
  658.     function getLabel({
  659.         return $this->getContent();
  660.     }
  661.  
  662.     /**
  663.      *    Test for a label match when searching.
  664.      *    @param string $label     Label to test.
  665.      *    @return boolean          True on match.
  666.      *    @access public
  667.      */
  668.     function isLabel($label{
  669.         return trim($label== trim($this->getLabel());
  670.     }
  671. }
  672.  
  673. /**
  674.  *    Content tag for text area.
  675.  *    @package SimpleTest
  676.  *    @subpackage WebTester
  677.  */
  678. class SimpleTextAreaTag extends SimpleWidget {
  679.  
  680.     /**
  681.      *    Starts with a named tag with attributes only.
  682.      *    @param hash $attributes    Attribute names and
  683.      *                                string values.
  684.      */
  685.     function __construct($attributes{
  686.         parent::__construct('textarea'$attributes);
  687.     }
  688.  
  689.     /**
  690.      *    Accessor for starting value.
  691.      *    @return string        Parsed value.
  692.      *    @access public
  693.      */
  694.     function getDefault({
  695.         return $this->wrap(html_entity_decode($this->getContent()ENT_QUOTES));
  696.     }
  697.  
  698.     /**
  699.      *    Applies word wrapping if needed.
  700.      *    @param string $value      New value.
  701.      *    @return boolean            True if allowed.
  702.      *    @access public
  703.      */
  704.     function setValue($value{
  705.         return parent::setValue($this->wrap($value));
  706.     }
  707.  
  708.     /**
  709.      *    Test to see if text should be wrapped.
  710.      *    @return boolean        True if wrapping on.
  711.      *    @access private
  712.      */
  713.     function wrapIsEnabled({
  714.         if ($this->getAttribute('cols')) {
  715.             $wrap $this->getAttribute('wrap');
  716.             if (($wrap == 'physical'|| ($wrap == 'hard')) {
  717.                 return true;
  718.             }
  719.         }
  720.         return false;
  721.     }
  722.  
  723.     /**
  724.      *    Performs the formatting that is peculiar to
  725.      *    this tag. There is strange behaviour in this
  726.      *    one, including stripping a leading new line.
  727.      *    Go figure. I am using Firefox as a guide.
  728.      *    @param string $text    Text to wrap.
  729.      *    @return string         Text wrapped with carriage
  730.      *                            returns and line feeds
  731.      *    @access private
  732.      */
  733.     protected function wrap($text{
  734.         $text str_replace("\r\r\n""\r\n"str_replace("\n""\r\n"$text));
  735.         $text str_replace("\r\n\n""\r\n"str_replace("\r""\r\n"$text));
  736.         if (strncmp($text"\r\n"strlen("\r\n")) == 0{
  737.             $text substr($textstrlen("\r\n"));
  738.         }
  739.         if ($this->wrapIsEnabled()) {
  740.             return wordwrap(
  741.                     $text,
  742.                     (integer)$this->getAttribute('cols'),
  743.                     "\r\n");
  744.         }
  745.         return $text;
  746.     }
  747.  
  748.     /**
  749.      *    The content of textarea is not part of the page.
  750.      *    @return boolean        True.
  751.      *    @access public
  752.      */
  753.     function isPrivateContent({
  754.         return true;
  755.     }
  756. }
  757.  
  758. /**
  759.  *    File upload widget.
  760.  *    @package SimpleTest
  761.  *    @subpackage WebTester
  762.  */
  763. class SimpleUploadTag extends SimpleWidget {
  764.  
  765.     /**
  766.      *    Starts with attributes only.
  767.      *    @param hash $attributes    Attribute names and
  768.      *                                string values.
  769.      */
  770.     function __construct($attributes{
  771.         parent::__construct('input'$attributes);
  772.     }
  773.  
  774.     /**
  775.      *    Tag contains no content.
  776.      *    @return boolean        False.
  777.      *    @access public
  778.      */
  779.     function expectEndTag({
  780.         return false;
  781.     }
  782.  
  783.     /**
  784.      *    Dispatches the value into the form encoded packet.
  785.      *    @param SimpleEncoding $encoding    Form packet.
  786.      *    @access public
  787.      */
  788.     function write($encoding{
  789.         if (file_exists($this->getValue())) {
  790.             return;
  791.         }
  792.         $encoding->attach(
  793.                 $this->getName(),
  794.                 implode(''file($this->getValue())),
  795.                 basename($this->getValue()));
  796.     }
  797. }
  798.  
  799. /**
  800.  *    Drop down widget.
  801.  *    @package SimpleTest
  802.  *    @subpackage WebTester
  803.  */
  804. class SimpleSelectionTag extends SimpleWidget {
  805.     private $options;
  806.     private $choice;
  807.  
  808.     /**
  809.      *    Starts with attributes only.
  810.      *    @param hash $attributes    Attribute names and
  811.      *                                string values.
  812.      */
  813.     function __construct($attributes{
  814.         parent::__construct('select'$attributes);
  815.         $this->options array();
  816.         $this->choice false;
  817.     }
  818.  
  819.     /**
  820.      *    Adds an option tag to a selection field.
  821.      *    @param SimpleOptionTag $tag     New option.
  822.      *    @access public
  823.      */
  824.     function addTag($tag{
  825.         if ($tag->getTagName(== 'option'{
  826.             $this->options[$tag;
  827.         }
  828.     }
  829.  
  830.     /**
  831.      *    Text within the selection element is ignored.
  832.      *    @param string $content        Ignored.
  833.      *    @access public
  834.      */
  835.     function addContent($content{
  836.         return $this;
  837.     }
  838.  
  839.     /**
  840.      *    Scans options for defaults. If none, then
  841.      *    the first option is selected.
  842.      *    @return string        Selected field.
  843.      *    @access public
  844.      */
  845.     function getDefault({
  846.         for ($i 0$count count($this->options)$i $count$i++{
  847.             if ($this->options[$i]->getAttribute('selected'!== false{
  848.                 return $this->options[$i]->getDefault();
  849.             }
  850.         }
  851.         if ($count 0{
  852.             return $this->options[0]->getDefault();
  853.         }
  854.         return '';
  855.     }
  856.  
  857.     /**
  858.      *    Can only set allowed values.
  859.      *    @param string $value       New choice.
  860.      *    @return boolean            True if allowed.
  861.      *    @access public
  862.      */
  863.     function setValue($value{
  864.         for ($i 0$count count($this->options)$i $count$i++{
  865.             if ($this->options[$i]->isValue($value)) {
  866.                 $this->choice $i;
  867.                 return true;
  868.             }
  869.         }
  870.         return false;
  871.     }
  872.  
  873.     /**
  874.      *    Accessor for current selection value.
  875.      *    @return string      Value attribute or
  876.      *                         content of opton.
  877.      *    @access public
  878.      */
  879.     function getValue({
  880.         if ($this->choice === false{
  881.             return $this->getDefault();
  882.         }
  883.         return $this->options[$this->choice]->getValue();
  884.     }
  885. }
  886.  
  887. /**
  888.  *    Drop down widget.
  889.  *    @package SimpleTest
  890.  *    @subpackage WebTester
  891.  */
  892.     private $options;
  893.     private $values;
  894.  
  895.     /**
  896.      *    Starts with attributes only.
  897.      *    @param hash $attributes    Attribute names and
  898.      *                                string values.
  899.      */
  900.     function __construct($attributes{
  901.         parent::__construct('select'$attributes);
  902.         $this->options array();
  903.         $this->values false;
  904.     }
  905.  
  906.     /**
  907.      *    Adds an option tag to a selection field.
  908.      *    @param SimpleOptionTag $tag     New option.
  909.      *    @access public
  910.      */
  911.     function addTag($tag{
  912.         if ($tag->getTagName(== 'option'{
  913.             $this->options[&$tag;
  914.         }
  915.     }
  916.  
  917.     /**
  918.      *    Text within the selection element is ignored.
  919.      *    @param string $content        Ignored.
  920.      *    @access public
  921.      */
  922.     function addContent($content{
  923.         return $this;
  924.     }
  925.  
  926.     /**
  927.      *    Scans options for defaults to populate the
  928.      *    value array().
  929.      *    @return array        Selected fields.
  930.      *    @access public
  931.      */
  932.     function getDefault({
  933.         $default array();
  934.         for ($i 0$count count($this->options)$i $count$i++{
  935.             if ($this->options[$i]->getAttribute('selected'!== false{
  936.                 $default[$this->options[$i]->getDefault();
  937.             }
  938.         }
  939.         return $default;
  940.     }
  941.  
  942.     /**
  943.      *    Can only set allowed values. Any illegal value
  944.      *    will result in a failure, but all correct values
  945.      *    will be set.
  946.      *    @param array $desired      New choices.
  947.      *    @return boolean            True if all allowed.
  948.      *    @access public
  949.      */
  950.     function setValue($desired{
  951.         $achieved array();
  952.         foreach ($desired as $value{
  953.             $success false;
  954.             for ($i 0$count count($this->options)$i $count$i++{
  955.                 if ($this->options[$i]->isValue($value)) {
  956.                     $achieved[$this->options[$i]->getValue();
  957.                     $success true;
  958.                     break;
  959.                 }
  960.             }
  961.             if ($success{
  962.                 return false;
  963.             }
  964.         }
  965.         $this->values $achieved;
  966.         return true;
  967.     }
  968.  
  969.     /**
  970.      *    Accessor for current selection value.
  971.      *    @return array      List of currently set options.
  972.      *    @access public
  973.      */
  974.     function getValue({
  975.         if ($this->values === false{
  976.             return $this->getDefault();
  977.         }
  978.         return $this->values;
  979.     }
  980. }
  981.  
  982. /**
  983.  *    Option for selection field.
  984.  *    @package SimpleTest
  985.  *    @subpackage WebTester
  986.  */
  987. class SimpleOptionTag extends SimpleWidget {
  988.  
  989.     /**
  990.      *    Stashes the attributes.
  991.      */
  992.     function __construct($attributes{
  993.         parent::__construct('option'$attributes);
  994.     }
  995.  
  996.     /**
  997.      *    Does nothing.
  998.      *    @param string $value      Ignored.
  999.      *    @return boolean           Not allowed.
  1000.      *    @access public
  1001.      */
  1002.     function setValue($value{
  1003.         return false;
  1004.     }
  1005.  
  1006.     /**
  1007.      *    Test to see if a value matches the option.
  1008.      *    @param string $compare    Value to compare with.
  1009.      *    @return boolean           True if possible match.
  1010.      *    @access public
  1011.      */
  1012.     function isValue($compare{
  1013.         $compare trim($compare);
  1014.         if (trim($this->getValue()) == $compare{
  1015.             return true;
  1016.         }
  1017.         return trim(strip_tags($this->getContent())) == $compare;
  1018.     }
  1019.  
  1020.     /**
  1021.      *    Accessor for starting value. Will be set to
  1022.      *    the option label if no value exists.
  1023.      *    @return string        Parsed value.
  1024.      *    @access public
  1025.      */
  1026.     function getDefault({
  1027.         if ($this->getAttribute('value'=== false{
  1028.             return strip_tags($this->getContent());
  1029.         }
  1030.         return $this->getAttribute('value');
  1031.     }
  1032.  
  1033.     /**
  1034.      *    The content of options is not part of the page.
  1035.      *    @return boolean        True.
  1036.      *    @access public
  1037.      */
  1038.     function isPrivateContent({
  1039.         return true;
  1040.     }
  1041. }
  1042.  
  1043. /**
  1044.  *    Radio button.
  1045.  *    @package SimpleTest
  1046.  *    @subpackage WebTester
  1047.  */
  1048.  
  1049.     /**
  1050.      *    Stashes the attributes.
  1051.      *    @param array $attributes        Hash of attributes.
  1052.      */
  1053.     function __construct($attributes{
  1054.         parent::__construct('input'$attributes);
  1055.         if ($this->getAttribute('value'=== false{
  1056.             $this->setAttribute('value''on');
  1057.         }
  1058.     }
  1059.  
  1060.     /**
  1061.      *    Tag contains no content.
  1062.      *    @return boolean        False.
  1063.      *    @access public
  1064.      */
  1065.     function expectEndTag({
  1066.         return false;
  1067.     }
  1068.  
  1069.     /**
  1070.      *    The only allowed value sn the one in the
  1071.      *    "value" attribute.
  1072.      *    @param string $value      New value.
  1073.      *    @return boolean           True if allowed.
  1074.      *    @access public
  1075.      */
  1076.     function setValue($value{
  1077.         if ($value === false{
  1078.             return parent::setValue($value);
  1079.         }
  1080.         if ($value != $this->getAttribute('value')) {
  1081.             return false;
  1082.         }
  1083.         return parent::setValue($value);
  1084.     }
  1085.  
  1086.     /**
  1087.      *    Accessor for starting value.
  1088.      *    @return string        Parsed value.
  1089.      *    @access public
  1090.      */
  1091.     function getDefault({
  1092.         if ($this->getAttribute('checked'!== false{
  1093.             return $this->getAttribute('value');
  1094.         }
  1095.         return false;
  1096.     }
  1097. }
  1098.  
  1099. /**
  1100.  *    Checkbox widget.
  1101.  *    @package SimpleTest
  1102.  *    @subpackage WebTester
  1103.  */
  1104. class SimpleCheckboxTag extends SimpleWidget {
  1105.  
  1106.     /**
  1107.      *    Starts with attributes only.
  1108.      *    @param hash $attributes    Attribute names and
  1109.      *                                string values.
  1110.      */
  1111.     function __construct($attributes{
  1112.         parent::__construct('input'$attributes);
  1113.         if ($this->getAttribute('value'=== false{
  1114.             $this->setAttribute('value''on');
  1115.         }
  1116.     }
  1117.  
  1118.     /**
  1119.      *    Tag contains no content.
  1120.      *    @return boolean        False.
  1121.      *    @access public
  1122.      */
  1123.     function expectEndTag({
  1124.         return false;
  1125.     }
  1126.  
  1127.     /**
  1128.      *    The only allowed value in the one in the
  1129.      *    "value" attribute. The default for this
  1130.      *    attribute is "on". If this widget is set to
  1131.      *    true, then the usual value will be taken.
  1132.      *    @param string $value      New value.
  1133.      *    @return boolean           True if allowed.
  1134.      *    @access public
  1135.      */
  1136.     function setValue($value{
  1137.         if ($value === false{
  1138.             return parent::setValue($value);
  1139.         }
  1140.         if ($value === true{
  1141.             return parent::setValue($this->getAttribute('value'));
  1142.         }
  1143.         if ($value != $this->getAttribute('value')) {
  1144.             return false;
  1145.         }
  1146.         return parent::setValue($value);
  1147.     }
  1148.  
  1149.     /**
  1150.      *    Accessor for starting value. The default
  1151.      *    value is "on".
  1152.      *    @return string        Parsed value.
  1153.      *    @access public
  1154.      */
  1155.     function getDefault({
  1156.         if ($this->getAttribute('checked'!== false{
  1157.             return $this->getAttribute('value');
  1158.         }
  1159.         return false;
  1160.     }
  1161. }
  1162.  
  1163. /**
  1164.  *    A group of multiple widgets with some shared behaviour.
  1165.  *    @package SimpleTest
  1166.  *    @subpackage WebTester
  1167.  */
  1168. class SimpleTagGroup {
  1169.     private $widgets array();
  1170.  
  1171.     /**
  1172.      *    Adds a tag to the group.
  1173.      *    @param SimpleWidget $widget 
  1174.      *    @access public
  1175.      */
  1176.     function addWidget($widget{
  1177.         $this->widgets[$widget;
  1178.     }
  1179.  
  1180.     /**
  1181.      *    Accessor to widget set.
  1182.      *    @return array        All widgets.
  1183.      *    @access protected
  1184.      */
  1185.     protected function &getWidgets({
  1186.         return $this->widgets;
  1187.     }
  1188.  
  1189.     /**
  1190.      *    Accessor for an attribute.
  1191.      *    @param string $label    Attribute name.
  1192.      *    @return boolean         Always false.
  1193.      *    @access public
  1194.      */
  1195.     function getAttribute($label{
  1196.         return false;
  1197.     }
  1198.  
  1199.     /**
  1200.      *    Fetches the name for the widget from the first
  1201.      *    member.
  1202.      *    @return string        Name of widget.
  1203.      *    @access public
  1204.      */
  1205.     function getName({
  1206.         if (count($this->widgets0{
  1207.             return $this->widgets[0]->getName();
  1208.         }
  1209.     }
  1210.  
  1211.     /**
  1212.      *    Scans the widgets for one with the appropriate
  1213.      *    ID field.
  1214.      *    @param string $id        ID value to try.
  1215.      *    @return boolean          True if matched.
  1216.      *    @access public
  1217.      */
  1218.     function isId($id{
  1219.         for ($i 0$count count($this->widgets)$i $count$i++{
  1220.             if ($this->widgets[$i]->isId($id)) {
  1221.                 return true;
  1222.             }
  1223.         }
  1224.         return false;
  1225.     }
  1226.  
  1227.     /**
  1228.      *    Scans the widgets for one with the appropriate
  1229.      *    attached label.
  1230.      *    @param string $label     Attached label to try.
  1231.      *    @return boolean          True if matched.
  1232.      *    @access public
  1233.      */
  1234.     function isLabel($label{
  1235.         for ($i 0$count count($this->widgets)$i $count$i++{
  1236.             if ($this->widgets[$i]->isLabel($label)) {
  1237.                 return true;
  1238.             }
  1239.         }
  1240.         return false;
  1241.     }
  1242.  
  1243.     /**
  1244.      *    Dispatches the value into the form encoded packet.
  1245.      *    @param SimpleEncoding $encoding    Form packet.
  1246.      *    @access public
  1247.      */
  1248.     function write($encoding{
  1249.         $encoding->add($this->getName()$this->getValue());
  1250.     }
  1251. }
  1252.  
  1253. /**
  1254.  *    A group of tags with the same name within a form.
  1255.  *    @package SimpleTest
  1256.  *    @subpackage WebTester
  1257.  */
  1258.  
  1259.     /**
  1260.      *    Accessor for current selected widget or false
  1261.      *    if none.
  1262.      *    @return string/array     Widget values or false if none.
  1263.      *    @access public
  1264.      */
  1265.     function getValue({
  1266.         $values array();
  1267.         $widgets $this->getWidgets();
  1268.         for ($i 0$count count($widgets)$i $count$i++{
  1269.             if ($widgets[$i]->getValue(!== false{
  1270.                 $values[$widgets[$i]->getValue();
  1271.             }
  1272.         }
  1273.         return $this->coerceValues($values);
  1274.     }
  1275.  
  1276.     /**
  1277.      *    Accessor for starting value that is active.
  1278.      *    @return string/array      Widget values or false if none.
  1279.      *    @access public
  1280.      */
  1281.     function getDefault({
  1282.         $values array();
  1283.         $widgets $this->getWidgets();
  1284.         for ($i 0$count count($widgets)$i $count$i++{
  1285.             if ($widgets[$i]->getDefault(!== false{
  1286.                 $values[$widgets[$i]->getDefault();
  1287.             }
  1288.         }
  1289.         return $this->coerceValues($values);
  1290.     }
  1291.  
  1292.     /**
  1293.      *    Accessor for current set values.
  1294.      *    @param string/array/boolean $values   Either a single string, a
  1295.      *                                           hash or false for nothing set.
  1296.      *    @return boolean                       True if all values can be set.
  1297.      *    @access public
  1298.      */
  1299.     function setValue($values{
  1300.         $values $this->makeArray($values);
  1301.         if ($this->valuesArePossible($values)) {
  1302.             return false;
  1303.         }
  1304.         $widgets $this->getWidgets();
  1305.         for ($i 0$count count($widgets)$i $count$i++{
  1306.             $possible $widgets[$i]->getAttribute('value');
  1307.             if (in_array($widgets[$i]->getAttribute('value')$values)) {
  1308.                 $widgets[$i]->setValue($possible);
  1309.             else {
  1310.                 $widgets[$i]->setValue(false);
  1311.             }
  1312.         }
  1313.         return true;
  1314.     }
  1315.  
  1316.     /**
  1317.      *    Tests to see if a possible value set is legal.
  1318.      *    @param string/array/boolean $values   Either a single string, a
  1319.      *                                           hash or false for nothing set.
  1320.      *    @return boolean                       False if trying to set a
  1321.      *                                           missing value.
  1322.      *    @access private
  1323.      */
  1324.     protected function valuesArePossible($values{
  1325.         $matches array();
  1326.         $widgets &$this->getWidgets();
  1327.         for ($i 0$count count($widgets)$i $count$i++{
  1328.             $possible $widgets[$i]->getAttribute('value');
  1329.             if (in_array($possible$values)) {
  1330.                 $matches[$possible;
  1331.             }
  1332.         }
  1333.         return ($values == $matches);
  1334.     }
  1335.  
  1336.     /**
  1337.      *    Converts the output to an appropriate format. This means
  1338.      *    that no values is false, a single value is just that
  1339.      *    value and only two or more are contained in an array.
  1340.      *    @param array $values           List of values of widgets.
  1341.      *    @return string/array/boolean   Expected format for a tag.
  1342.      *    @access private
  1343.      */
  1344.     protected function coerceValues($values{
  1345.         if (count($values== 0{
  1346.             return false;
  1347.         elseif (count($values== 1{
  1348.             return $values[0];
  1349.         else {
  1350.             return $values;
  1351.         }
  1352.     }
  1353.  
  1354.     /**
  1355.      *    Converts false or string into array. The opposite of
  1356.      *    the coercian method.
  1357.      *    @param string/array/boolean $value  A single item is converted
  1358.      *                                         to a one item list. False
  1359.      *                                         gives an empty list.
  1360.      *    @return array                       List of values, possibly empty.
  1361.      *    @access private
  1362.      */
  1363.     protected function makeArray($value{
  1364.         if ($value === false{
  1365.             return array();
  1366.         }
  1367.         if (is_string($value)) {
  1368.             return array($value);
  1369.         }
  1370.         return $value;
  1371.     }
  1372. }
  1373.  
  1374. /**
  1375.  *    A group of tags with the same name within a form.
  1376.  *    Used for radio buttons.
  1377.  *    @package SimpleTest
  1378.  *    @subpackage WebTester
  1379.  */
  1380. class SimpleRadioGroup extends SimpleTagGroup {
  1381.  
  1382.     /**
  1383.      *    Each tag is tried in turn until one is
  1384.      *    successfully set. The others will be
  1385.      *    unchecked if successful.
  1386.      *    @param string $value      New value.
  1387.      *    @return boolean           True if any allowed.
  1388.      *    @access public
  1389.      */
  1390.     function setValue($value{
  1391.         if ($this->valueIsPossible($value)) {
  1392.             return false;
  1393.         }
  1394.         $index false;
  1395.         $widgets $this->getWidgets();
  1396.         for ($i 0$count count($widgets)$i $count$i++{
  1397.             if ($widgets[$i]->setValue($value)) {
  1398.                 $widgets[$i]->setValue(false);
  1399.             }
  1400.         }
  1401.         return true;
  1402.     }
  1403.  
  1404.     /**
  1405.      *    Tests to see if a value is allowed.
  1406.      *    @param string    Attempted value.
  1407.      *    @return boolean  True if a valid value.
  1408.      *    @access private
  1409.      */
  1410.     protected function valueIsPossible($value{
  1411.         $widgets $this->getWidgets();
  1412.         for ($i 0$count count($widgets)$i $count$i++{
  1413.             if ($widgets[$i]->getAttribute('value'== $value{
  1414.                 return true;
  1415.             }
  1416.         }
  1417.         return false;
  1418.     }
  1419.  
  1420.     /**
  1421.      *    Accessor for current selected widget or false
  1422.      *    if none.
  1423.      *    @return string/boolean   Value attribute or
  1424.      *                              content of opton.
  1425.      *    @access public
  1426.      */
  1427.     function getValue({
  1428.         $widgets $this->getWidgets();
  1429.         for ($i 0$count count($widgets)$i $count$i++{
  1430.             if ($widgets[$i]->getValue(!== false{
  1431.                 return $widgets[$i]->getValue();
  1432.             }
  1433.         }
  1434.         return false;
  1435.     }
  1436.  
  1437.     /**
  1438.      *    Accessor for starting value that is active.
  1439.      *    @return string/boolean      Value of first checked
  1440.      *                                 widget or false if none.
  1441.      *    @access public
  1442.      */
  1443.     function getDefault({
  1444.         $widgets $this->getWidgets();
  1445.         for ($i 0$count count($widgets)$i $count$i++{
  1446.             if ($widgets[$i]->getDefault(!== false{
  1447.                 return $widgets[$i]->getDefault();
  1448.             }
  1449.         }
  1450.         return false;
  1451.     }
  1452. }
  1453.  
  1454. /**
  1455.  *    Tag to keep track of labels.
  1456.  *    @package SimpleTest
  1457.  *    @subpackage WebTester
  1458.  */
  1459. class SimpleLabelTag extends SimpleTag {
  1460.  
  1461.     /**
  1462.      *    Starts with a named tag with attributes only.
  1463.      *    @param hash $attributes    Attribute names and
  1464.      *                                string values.
  1465.      */
  1466.     function __construct($attributes{
  1467.         parent::__construct('label'$attributes);
  1468.     }
  1469.  
  1470.     /**
  1471.      *    Access for the ID to attach the label to.
  1472.      *    @return string        For attribute.
  1473.      *    @access public
  1474.      */
  1475.     function getFor({
  1476.         return $this->getAttribute('for');
  1477.     }
  1478. }
  1479.  
  1480. /**
  1481.  *    Tag to aid parsing the form.
  1482.  *    @package SimpleTest
  1483.  *    @subpackage WebTester
  1484.  */
  1485. class SimpleFormTag extends SimpleTag {
  1486.  
  1487.     /**
  1488.      *    Starts with a named tag with attributes only.
  1489.      *    @param hash $attributes    Attribute names and
  1490.      *                                string values.
  1491.      */
  1492.     function __construct($attributes{
  1493.         parent::__construct('form'$attributes);
  1494.     }
  1495. }
  1496.  
  1497. /**
  1498.  *    Tag to aid parsing the frames in a page.
  1499.  *    @package SimpleTest
  1500.  *    @subpackage WebTester
  1501.  */
  1502. class SimpleFrameTag extends SimpleTag {
  1503.  
  1504.     /**
  1505.      *    Starts with a named tag with attributes only.
  1506.      *    @param hash $attributes    Attribute names and
  1507.      *                                string values.
  1508.      */
  1509.     function __construct($attributes{
  1510.         parent::__construct('frame'$attributes);
  1511.     }
  1512.  
  1513.     /**
  1514.      *    Tag contains no content.
  1515.      *    @return boolean        False.
  1516.      *    @access public
  1517.      */
  1518.     function expectEndTag({
  1519.         return false;
  1520.     }
  1521. }
  1522. ?>

Documentation generated on Sun, 31 Oct 2010 16:32:34 -0500 by phpDocumentor 1.4.3