Source for file web_tester.php

Documentation is available at web_tester.php

  1. <?php
  2. /**
  3.  *  Base include file for SimpleTest.
  4.  *  @package    SimpleTest
  5.  *  @subpackage WebTester
  6.  *  @version    $Id: web_tester.php 1723 2008-04-08 00:34:10Z lastcraft $
  7.  */
  8.  
  9. /**#@+
  10.  *  include other SimpleTest class files
  11.  */
  12. require_once(dirname(__FILE__'/test_case.php');
  13. require_once(dirname(__FILE__'/browser.php');
  14. require_once(dirname(__FILE__'/page.php');
  15. require_once(dirname(__FILE__'/expectation.php');
  16. /**#@-*/
  17.  
  18.  *    Test for an HTML widget value match.
  19.  *    @package SimpleTest
  20.  *    @subpackage WebTester
  21.  */
  22.     var $_value;
  23.     
  24.     /**
  25.      *    Sets the field value to compare against.
  26.      *    @param mixed $value     Test value to match. Can be an
  27.      *                             expectation for say pattern matching.
  28.      *    @param string $message  Optiona message override. Can use %s as
  29.      *                             a placeholder for the original message.
  30.      *    @access public
  31.      */
  32.     function FieldExpectation($value$message '%s'{
  33.         $this->SimpleExpectation($message);
  34.         if (is_array($value)) {
  35.             sort($value);
  36.         }
  37.         $this->_value = $value;
  38.     }
  39.     
  40.     /**
  41.      *    Tests the expectation. True if it matches
  42.      *    a string value or an array value in any order.
  43.      *    @param mixed $compare        Comparison value. False for
  44.      *                                  an unset field.
  45.      *    @return boolean              True if correct.
  46.      *    @access public
  47.      */
  48.     function test($compare{
  49.         if ($this->_value === false{
  50.             return ($compare === false);
  51.         }
  52.         if ($this->_isSingle($this->_value)) {
  53.             return $this->_testSingle($compare);
  54.         }
  55.         if (is_array($this->_value)) {
  56.             return $this->_testMultiple($compare);
  57.         }
  58.         return false;
  59.     }
  60.     
  61.     /**
  62.      *    Tests for valid field comparisons with a single option.
  63.      *    @param mixed $value       Value to type check.
  64.      *    @return boolean           True if integer, string or float.
  65.      *    @access private
  66.      */
  67.     function _isSingle($value{
  68.         return is_string($value|| is_integer($value|| is_float($value);
  69.     }
  70.     
  71.     /**
  72.      *    String comparison for simple field with a single option.
  73.      *    @param mixed $compare    String to test against.
  74.      *    @returns boolean         True if matching.
  75.      *    @access private
  76.      */
  77.     function _testSingle($compare{
  78.         if (is_array($compare&& count($compare== 1{
  79.             $compare $compare[0];
  80.         }
  81.         if ($this->_isSingle($compare)) {
  82.             return false;
  83.         }
  84.         return ($this->_value == $compare);
  85.     }
  86.     
  87.     /**
  88.      *    List comparison for multivalue field.
  89.      *    @param mixed $compare    List in any order to test against.
  90.      *    @returns boolean         True if matching.
  91.      *    @access private
  92.      */
  93.     function _testMultiple($compare{
  94.         if (is_string($compare)) {
  95.             $compare array($compare);
  96.         }
  97.         if (is_array($compare)) {
  98.             return false;
  99.         }
  100.         sort($compare);
  101.         return ($this->_value === $compare);
  102.     }
  103.     
  104.     /**
  105.      *    Returns a human readable test message.
  106.      *    @param mixed $compare      Comparison value.
  107.      *    @return string             Description of success
  108.      *                                or failure.
  109.      *    @access public
  110.      */
  111.     function testMessage($compare{
  112.         $dumper &$this->_getDumper();
  113.         if (is_array($compare)) {
  114.             sort($compare);
  115.         }
  116.         if ($this->test($compare)) {
  117.             return "Field expectation [" $dumper->describeValue($this->_value"]";
  118.         else {
  119.             return "Field expectation [" $dumper->describeValue($this->_value.
  120.                     "] fails with [" .
  121.                     $dumper->describeValue($compare"] " .
  122.                     $dumper->describeDifference($this->_value$compare);
  123.         }
  124.     }
  125. }
  126.  
  127. /**
  128.  *    Test for a specific HTTP header within a header block.
  129.  *    @package SimpleTest
  130.  *    @subpackage WebTester
  131.  */
  132.     var $_expected_header;
  133.     var $_expected_value;
  134.     
  135.     /**
  136.      *    Sets the field and value to compare against.
  137.      *    @param string $header   Case insenstive trimmed header name.
  138.      *    @param mixed $value     Optional value to compare. If not
  139.      *                             given then any value will match. If
  140.      *                             an expectation object then that will
  141.      *                             be used instead.
  142.      *    @param string $message  Optiona message override. Can use %s as
  143.      *                             a placeholder for the original message.
  144.      */
  145.     function HttpHeaderExpectation($header$value false$message '%s'{
  146.         $this->SimpleExpectation($message);
  147.         $this->_expected_header = $this->_normaliseHeader($header);
  148.         $this->_expected_value = $value;
  149.     }
  150.     
  151.     /**
  152.      *    Accessor for aggregated object.
  153.      *    @return mixed        Expectation set in constructor.
  154.      *    @access protected
  155.      */
  156.     function _getExpectation({
  157.         return $this->_expected_value;
  158.     }
  159.     
  160.     /**
  161.      *    Removes whitespace at ends and case variations.
  162.      *    @param string $header    Name of header.
  163.      *    @param string            Trimmed and lowecased header
  164.      *                              name.
  165.      *    @access private
  166.      */
  167.     function _normaliseHeader($header{
  168.         return strtolower(trim($header));
  169.     }
  170.     
  171.     /**
  172.      *    Tests the expectation. True if it matches
  173.      *    a string value or an array value in any order.
  174.      *    @param mixed $compare   Raw header block to search.
  175.      *    @return boolean         True if header present.
  176.      *    @access public
  177.      */
  178.     function test($compare{
  179.         return is_string($this->_findHeader($compare));
  180.     }
  181.     
  182.     /**
  183.      *    Searches the incoming result. Will extract the matching
  184.      *    line as text.
  185.      *    @param mixed $compare   Raw header block to search.
  186.      *    @return string          Matching header line.
  187.      *    @access protected
  188.      */
  189.     function _findHeader($compare{
  190.         $lines split("\r\n"$compare);
  191.         foreach ($lines as $line{
  192.             if ($this->_testHeaderLine($line)) {
  193.                 return $line;
  194.             }
  195.         }
  196.         return false;
  197.     }
  198.     
  199.     /**
  200.      *    Compares a single header line against the expectation.
  201.      *    @param string $line      A single line to compare.
  202.      *    @return boolean          True if matched.
  203.      *    @access private
  204.      */
  205.     function _testHeaderLine($line{
  206.         if (count($parsed split(':'$line2)) 2{
  207.             return false;
  208.         }
  209.         list($header$value$parsed;
  210.         if ($this->_normaliseHeader($header!= $this->_expected_header{
  211.             return false;
  212.         }
  213.         return $this->_testHeaderValue($value$this->_expected_value);
  214.     }
  215.     
  216.     /**
  217.      *    Tests the value part of the header.
  218.      *    @param string $value        Value to test.
  219.      *    @param mixed $expected      Value to test against.
  220.      *    @return boolean             True if matched.
  221.      *    @access protected
  222.      */
  223.     function _testHeaderValue($value$expected{
  224.         if ($expected === false{
  225.             return true;
  226.         }
  227.         if (SimpleExpectation::isExpectation($expected)) {
  228.             return $expected->test(trim($value));
  229.         }
  230.         return (trim($value== trim($expected));
  231.     }
  232.     
  233.     /**
  234.      *    Returns a human readable test message.
  235.      *    @param mixed $compare      Raw header block to search.
  236.      *    @return string             Description of success
  237.      *                                or failure.
  238.      *    @access public
  239.      */
  240.     function testMessage($compare{
  241.         if (SimpleExpectation::isExpectation($this->_expected_value)) {
  242.             $message $this->_expected_value->overlayMessage($compare$this->_getDumper());
  243.         else {
  244.             $message $this->_expected_header .
  245.                     ($this->_expected_value ? ': ' $this->_expected_value : '');
  246.         }
  247.         if (is_string($line $this->_findHeader($compare))) {
  248.             return "Searching for header [$message] found [$line]";
  249.         else {
  250.             return "Failed to find header [$message]";
  251.         }
  252.     }
  253. }
  254.     
  255. /**
  256.  *    Test for a specific HTTP header within a header block that
  257.  *    should not be found.
  258.  *    @package SimpleTest
  259.  *    @subpackage WebTester
  260.  */
  261.     var $_expected_header;
  262.     var $_expected_value;
  263.     
  264.     /**
  265.      *    Sets the field and value to compare against.
  266.      *    @param string $unwanted   Case insenstive trimmed header name.
  267.      *    @param string $message    Optiona message override. Can use %s as
  268.      *                               a placeholder for the original message.
  269.      */
  270.     function NoHttpHeaderExpectation($unwanted$message '%s'{
  271.         $this->HttpHeaderExpectation($unwantedfalse$message);
  272.     }
  273.     
  274.     /**
  275.      *    Tests that the unwanted header is not found.
  276.      *    @param mixed $compare   Raw header block to search.
  277.      *    @return boolean         True if header present.
  278.      *    @access public
  279.      */
  280.     function test($compare{
  281.         return ($this->_findHeader($compare=== false);
  282.     }
  283.     
  284.     /**
  285.      *    Returns a human readable test message.
  286.      *    @param mixed $compare      Raw header block to search.
  287.      *    @return string             Description of success
  288.      *                                or failure.
  289.      *    @access public
  290.      */
  291.     function testMessage($compare{
  292.         $expectation $this->_getExpectation();
  293.         if (is_string($line $this->_findHeader($compare))) {
  294.             return "Found unwanted header [$expectation] with [$line]";
  295.         else {
  296.             return "Did not find unwanted header [$expectation]";
  297.         }
  298.     }
  299. }
  300.  
  301. /**
  302.  *    Test for a text substring.
  303.  *    @package SimpleTest
  304.  *    @subpackage UnitTester
  305.  */
  306.     var $_substring;
  307.     
  308.     /**
  309.      *    Sets the value to compare against.
  310.      *    @param string $substring  Text to search for.
  311.      *    @param string $message    Customised message on failure.
  312.      *    @access public
  313.      */
  314.     function TextExpectation($substring$message '%s'{
  315.         $this->SimpleExpectation($message);
  316.         $this->_substring = $substring;
  317.     }
  318.     
  319.     /**
  320.      *    Accessor for the substring.
  321.      *    @return string       Text to match.
  322.      *    @access protected
  323.      */
  324.     function _getSubstring({
  325.         return $this->_substring;
  326.     }
  327.     
  328.     /**
  329.      *    Tests the expectation. True if the text contains the
  330.      *    substring.
  331.      *    @param string $compare        Comparison value.
  332.      *    @return boolean               True if correct.
  333.      *    @access public
  334.      */
  335.     function test($compare{
  336.         return (strpos($compare$this->_substring!== false);
  337.     }
  338.     
  339.     /**
  340.      *    Returns a human readable test message.
  341.      *    @param mixed $compare      Comparison value.
  342.      *    @return string             Description of success
  343.      *                                or failure.
  344.      *    @access public
  345.      */
  346.     function testMessage($compare{
  347.         if ($this->test($compare)) {
  348.             return $this->_describeTextMatch($this->_getSubstring()$compare);
  349.         else {
  350.             $dumper &$this->_getDumper();
  351.             return "Text [" $this->_getSubstring(.
  352.                     "] not detected in [" .
  353.                     $dumper->describeValue($compare"]";
  354.         }
  355.     }
  356.     
  357.     /**
  358.      *    Describes a pattern match including the string
  359.      *    found and it's position.
  360.      *    @param string $substring      Text to search for.
  361.      *    @param string $subject        Subject to search.
  362.      *    @access protected
  363.      */
  364.     function _describeTextMatch($substring$subject{
  365.         $position strpos($subject$substring);
  366.         $dumper &$this->_getDumper();
  367.         return "Text [$substring] detected at character [$position] in [.
  368.                 $dumper->describeValue($subject"] in region [" .
  369.                 $dumper->clipString($subject100$position"]";
  370.     }
  371. }
  372.  
  373. /**
  374.  *    Fail if a substring is detected within the
  375.  *    comparison text.
  376.  *    @package SimpleTest
  377.  *    @subpackage UnitTester
  378.  */
  379.     
  380.     /**
  381.      *    Sets the reject pattern
  382.      *    @param string $substring  Text to search for.
  383.      *    @param string $message    Customised message on failure.
  384.      *    @access public
  385.      */
  386.     function NoTextExpectation($substring$message '%s'{
  387.         $this->TextExpectation($substring$message);
  388.     }
  389.     
  390.     /**
  391.      *    Tests the expectation. False if the substring appears
  392.      *    in the text.
  393.      *    @param string $compare        Comparison value.
  394.      *    @return boolean               True if correct.
  395.      *    @access public
  396.      */
  397.     function test($compare{
  398.         return parent::test($compare);
  399.     }
  400.     
  401.     /**
  402.      *    Returns a human readable test message.
  403.      *    @param string $compare      Comparison value.
  404.      *    @return string              Description of success
  405.      *                                 or failure.
  406.      *    @access public
  407.      */
  408.     function testMessage($compare{
  409.         if ($this->test($compare)) {
  410.             $dumper &$this->_getDumper();
  411.             return "Text [" $this->_getSubstring(.
  412.                     "] not detected in [" .
  413.                     $dumper->describeValue($compare"]";
  414.         else {
  415.             return $this->_describeTextMatch($this->_getSubstring()$compare);
  416.         }
  417.     }
  418. }
  419.  
  420. /**
  421.  *    Test case for testing of web pages. Allows
  422.  *    fetching of pages, parsing of HTML and
  423.  *    submitting forms.
  424.  *    @package SimpleTest
  425.  *    @subpackage WebTester
  426.  */
  427. class WebTestCase extends SimpleTestCase {
  428.     var $_browser;
  429.     var $_ignore_errors = false;
  430.     
  431.     /**
  432.      *    Creates an empty test case. Should be subclassed
  433.      *    with test methods for a functional test case.
  434.      *    @param string $label     Name of test case. Will use
  435.      *                              the class name if none specified.
  436.      *    @access public
  437.      */
  438.     function WebTestCase($label false{
  439.         $this->SimpleTestCase($label);
  440.     }
  441.     
  442.     /**
  443.      *    Announces the start of the test.
  444.      *    @param string $method    Test method just started.
  445.      *    @access public
  446.      */
  447.     function before($method{
  448.         parent::before($method);
  449.         $this->setBrowser($this->createBrowser());
  450.     }
  451.  
  452.     /**
  453.      *    Announces the end of the test. Includes private clean up.
  454.      *    @param string $method    Test method just finished.
  455.      *    @access public
  456.      */
  457.     function after($method{
  458.         $this->unsetBrowser();
  459.         parent::after($method);
  460.     }
  461.     
  462.     /**
  463.      *    Gets a current browser reference for setting
  464.      *    special expectations or for detailed
  465.      *    examination of page fetches.
  466.      *    @return SimpleBrowser     Current test browser object.
  467.      *    @access public
  468.      */
  469.     function &getBrowser({
  470.         return $this->_browser;
  471.     }
  472.     
  473.     /**
  474.      *    Gets a current browser reference for setting
  475.      *    special expectations or for detailed
  476.      *    examination of page fetches.
  477.      *    @param SimpleBrowser $browser    New test browser object.
  478.      *    @access public
  479.      */
  480.     function setBrowser(&$browser{
  481.         return $this->_browser = &$browser;
  482.     }
  483.         
  484.     /**
  485.      *    Clears the current browser reference to help the
  486.      *    PHP garbage collector.
  487.      *    @access public
  488.      */
  489.     function unsetBrowser({
  490.         unset($this->_browser);
  491.     }
  492.     
  493.     /**
  494.      *    Creates a new default web browser object.
  495.      *    Will be cleared at the end of the test method.
  496.      *    @return TestBrowser           New browser.
  497.      *    @access public
  498.      */
  499.     function &createBrowser({
  500.         $browser &new SimpleBrowser();
  501.         return $browser;
  502.     }
  503.     
  504.     /**
  505.      *    Gets the last response error.
  506.      *    @return string    Last low level HTTP error.
  507.      *    @access public
  508.      */
  509.     function getTransportError({
  510.         return $this->_browser->getTransportError();
  511.     }
  512.         
  513.     /**
  514.      *    Accessor for the currently selected URL.
  515.      * &n