source: trunk/server/www/vendors/simpletest/web_tester.php @ 6

Last change on this file since 6 was 6, checked in by sander, 12 years ago

Added SimpleTest? test framework

File size: 53.5 KB
Line 
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 */
12require_once(dirname(__FILE__) . '/test_case.php');
13require_once(dirname(__FILE__) . '/browser.php');
14require_once(dirname(__FILE__) . '/page.php');
15require_once(dirname(__FILE__) . '/expectation.php');
16/**#@-*/
17
18/**
19 *    Test for an HTML widget value match.
20 *    @package SimpleTest
21 *    @subpackage WebTester
22 */
23class FieldExpectation extends SimpleExpectation {
24    var $_value;
25   
26    /**
27     *    Sets the field value to compare against.
28     *    @param mixed $value     Test value to match. Can be an
29     *                            expectation for say pattern matching.
30     *    @param string $message  Optiona message override. Can use %s as
31     *                            a placeholder for the original message.
32     *    @access public
33     */
34    function FieldExpectation($value, $message = '%s') {
35        $this->SimpleExpectation($message);
36        if (is_array($value)) {
37            sort($value);
38        }
39        $this->_value = $value;
40    }
41   
42    /**
43     *    Tests the expectation. True if it matches
44     *    a string value or an array value in any order.
45     *    @param mixed $compare        Comparison value. False for
46     *                                 an unset field.
47     *    @return boolean              True if correct.
48     *    @access public
49     */
50    function test($compare) {
51        if ($this->_value === false) {
52            return ($compare === false);
53        }
54        if ($this->_isSingle($this->_value)) {
55            return $this->_testSingle($compare);
56        }
57        if (is_array($this->_value)) {
58            return $this->_testMultiple($compare);
59        }
60        return false;
61    }
62   
63    /**
64     *    Tests for valid field comparisons with a single option.
65     *    @param mixed $value       Value to type check.
66     *    @return boolean           True if integer, string or float.
67     *    @access private
68     */
69    function _isSingle($value) {
70        return is_string($value) || is_integer($value) || is_float($value);
71    }
72   
73    /**
74     *    String comparison for simple field with a single option.
75     *    @param mixed $compare    String to test against.
76     *    @returns boolean         True if matching.
77     *    @access private
78     */
79    function _testSingle($compare) {
80        if (is_array($compare) && count($compare) == 1) {
81            $compare = $compare[0];
82        }
83        if (! $this->_isSingle($compare)) {
84            return false;
85        }
86        return ($this->_value == $compare);
87    }
88   
89    /**
90     *    List comparison for multivalue field.
91     *    @param mixed $compare    List in any order to test against.
92     *    @returns boolean         True if matching.
93     *    @access private
94     */
95    function _testMultiple($compare) {
96        if (is_string($compare)) {
97            $compare = array($compare);
98        }
99        if (! is_array($compare)) {
100            return false;
101        }
102        sort($compare);
103        return ($this->_value === $compare);
104    }
105   
106    /**
107     *    Returns a human readable test message.
108     *    @param mixed $compare      Comparison value.
109     *    @return string             Description of success
110     *                               or failure.
111     *    @access public
112     */
113    function testMessage($compare) {
114        $dumper = &$this->_getDumper();
115        if (is_array($compare)) {
116            sort($compare);
117        }
118        if ($this->test($compare)) {
119            return "Field expectation [" . $dumper->describeValue($this->_value) . "]";
120        } else {
121            return "Field expectation [" . $dumper->describeValue($this->_value) .
122                    "] fails with [" .
123                    $dumper->describeValue($compare) . "] " .
124                    $dumper->describeDifference($this->_value, $compare);
125        }
126    }
127}
128
129/**
130 *    Test for a specific HTTP header within a header block.
131 *    @package SimpleTest
132 *    @subpackage WebTester
133 */
134class HttpHeaderExpectation extends SimpleExpectation {
135    var $_expected_header;
136    var $_expected_value;
137   
138    /**
139     *    Sets the field and value to compare against.
140     *    @param string $header   Case insenstive trimmed header name.
141     *    @param mixed $value     Optional value to compare. If not
142     *                            given then any value will match. If
143     *                            an expectation object then that will
144     *                            be used instead.
145     *    @param string $message  Optiona message override. Can use %s as
146     *                            a placeholder for the original message.
147     */
148    function HttpHeaderExpectation($header, $value = false, $message = '%s') {
149        $this->SimpleExpectation($message);
150        $this->_expected_header = $this->_normaliseHeader($header);
151        $this->_expected_value = $value;
152    }
153   
154    /**
155     *    Accessor for aggregated object.
156     *    @return mixed        Expectation set in constructor.
157     *    @access protected
158     */
159    function _getExpectation() {
160        return $this->_expected_value;
161    }
162   
163    /**
164     *    Removes whitespace at ends and case variations.
165     *    @param string $header    Name of header.
166     *    @param string            Trimmed and lowecased header
167     *                             name.
168     *    @access private
169     */
170    function _normaliseHeader($header) {
171        return strtolower(trim($header));
172    }
173   
174    /**
175     *    Tests the expectation. True if it matches
176     *    a string value or an array value in any order.
177     *    @param mixed $compare   Raw header block to search.
178     *    @return boolean         True if header present.
179     *    @access public
180     */
181    function test($compare) {
182        return is_string($this->_findHeader($compare));
183    }
184   
185    /**
186     *    Searches the incoming result. Will extract the matching
187     *    line as text.
188     *    @param mixed $compare   Raw header block to search.
189     *    @return string          Matching header line.
190     *    @access protected
191     */
192    function _findHeader($compare) {
193        $lines = split("\r\n", $compare);
194        foreach ($lines as $line) {
195            if ($this->_testHeaderLine($line)) {
196                return $line;
197            }
198        }
199        return false;
200    }
201   
202    /**
203     *    Compares a single header line against the expectation.
204     *    @param string $line      A single line to compare.
205     *    @return boolean          True if matched.
206     *    @access private
207     */
208    function _testHeaderLine($line) {
209        if (count($parsed = split(':', $line, 2)) < 2) {
210            return false;
211        }
212        list($header, $value) = $parsed;
213        if ($this->_normaliseHeader($header) != $this->_expected_header) {
214            return false;
215        }
216        return $this->_testHeaderValue($value, $this->_expected_value);
217    }
218   
219    /**
220     *    Tests the value part of the header.
221     *    @param string $value        Value to test.
222     *    @param mixed $expected      Value to test against.
223     *    @return boolean             True if matched.
224     *    @access protected
225     */
226    function _testHeaderValue($value, $expected) {
227        if ($expected === false) {
228            return true;
229        }
230        if (SimpleExpectation::isExpectation($expected)) {
231            return $expected->test(trim($value));
232        }
233        return (trim($value) == trim($expected));
234    }
235   
236    /**
237     *    Returns a human readable test message.
238     *    @param mixed $compare      Raw header block to search.
239     *    @return string             Description of success
240     *                               or failure.
241     *    @access public
242     */
243    function testMessage($compare) {
244        if (SimpleExpectation::isExpectation($this->_expected_value)) {
245            $message = $this->_expected_value->overlayMessage($compare, $this->_getDumper());
246        } else {
247            $message = $this->_expected_header .
248                    ($this->_expected_value ? ': ' . $this->_expected_value : '');
249        }
250        if (is_string($line = $this->_findHeader($compare))) {
251            return "Searching for header [$message] found [$line]";
252        } else {
253            return "Failed to find header [$message]";
254        }
255    }
256}
257   
258/**
259 *    Test for a specific HTTP header within a header block that
260 *    should not be found.
261 *    @package SimpleTest
262 *    @subpackage WebTester
263 */
264class NoHttpHeaderExpectation extends HttpHeaderExpectation {
265    var $_expected_header;
266    var $_expected_value;
267   
268    /**
269     *    Sets the field and value to compare against.
270     *    @param string $unwanted   Case insenstive trimmed header name.
271     *    @param string $message    Optiona message override. Can use %s as
272     *                              a placeholder for the original message.
273     */
274    function NoHttpHeaderExpectation($unwanted, $message = '%s') {
275        $this->HttpHeaderExpectation($unwanted, false, $message);
276    }
277   
278    /**
279     *    Tests that the unwanted header is not found.
280     *    @param mixed $compare   Raw header block to search.
281     *    @return boolean         True if header present.
282     *    @access public
283     */
284    function test($compare) {
285        return ($this->_findHeader($compare) === false);
286    }
287   
288    /**
289     *    Returns a human readable test message.
290     *    @param mixed $compare      Raw header block to search.
291     *    @return string             Description of success
292     *                               or failure.
293     *    @access public
294     */
295    function testMessage($compare) {
296        $expectation = $this->_getExpectation();
297        if (is_string($line = $this->_findHeader($compare))) {
298            return "Found unwanted header [$expectation] with [$line]";
299        } else {
300            return "Did not find unwanted header [$expectation]";
301        }
302    }
303}
304
305/**
306 *    Test for a text substring.
307 *    @package SimpleTest
308 *    @subpackage UnitTester
309 */
310class TextExpectation extends SimpleExpectation {
311    var $_substring;
312   
313    /**
314     *    Sets the value to compare against.
315     *    @param string $substring  Text to search for.
316     *    @param string $message    Customised message on failure.
317     *    @access public
318     */
319    function TextExpectation($substring, $message = '%s') {
320        $this->SimpleExpectation($message);
321        $this->_substring = $substring;
322    }
323   
324    /**
325     *    Accessor for the substring.
326     *    @return string       Text to match.
327     *    @access protected
328     */
329    function _getSubstring() {
330        return $this->_substring;
331    }
332   
333    /**
334     *    Tests the expectation. True if the text contains the
335     *    substring.
336     *    @param string $compare        Comparison value.
337     *    @return boolean               True if correct.
338     *    @access public
339     */
340    function test($compare) {
341        return (strpos($compare, $this->_substring) !== false);
342    }
343   
344    /**
345     *    Returns a human readable test message.
346     *    @param mixed $compare      Comparison value.
347     *    @return string             Description of success
348     *                               or failure.
349     *    @access public
350     */
351    function testMessage($compare) {
352        if ($this->test($compare)) {
353            return $this->_describeTextMatch($this->_getSubstring(), $compare);
354        } else {
355            $dumper = &$this->_getDumper();
356            return "Text [" . $this->_getSubstring() .
357                    "] not detected in [" .
358                    $dumper->describeValue($compare) . "]";
359        }
360    }
361   
362    /**
363     *    Describes a pattern match including the string
364     *    found and it's position.
365     *    @param string $substring      Text to search for.
366     *    @param string $subject        Subject to search.
367     *    @access protected
368     */
369    function _describeTextMatch($substring, $subject) {
370        $position = strpos($subject, $substring);
371        $dumper = &$this->_getDumper();
372        return "Text [$substring] detected at character [$position] in [" .
373                $dumper->describeValue($subject) . "] in region [" .
374                $dumper->clipString($subject, 100, $position) . "]";
375    }
376}
377
378/**
379 *    Fail if a substring is detected within the
380 *    comparison text.
381 *    @package SimpleTest
382 *    @subpackage UnitTester
383 */
384class NoTextExpectation extends TextExpectation {
385   
386    /**
387     *    Sets the reject pattern
388     *    @param string $substring  Text to search for.
389     *    @param string $message    Customised message on failure.
390     *    @access public
391     */
392    function NoTextExpectation($substring, $message = '%s') {
393        $this->TextExpectation($substring, $message);
394    }
395   
396    /**
397     *    Tests the expectation. False if the substring appears
398     *    in the text.
399     *    @param string $compare        Comparison value.
400     *    @return boolean               True if correct.
401     *    @access public
402     */
403    function test($compare) {
404        return ! parent::test($compare);
405    }
406   
407    /**
408     *    Returns a human readable test message.
409     *    @param string $compare      Comparison value.
410     *    @return string              Description of success
411     *                                or failure.
412     *    @access public
413     */
414    function testMessage($compare) {
415        if ($this->test($compare)) {
416            $dumper = &$this->_getDumper();
417            return "Text [" . $this->_getSubstring() .
418                    "] not detected in [" .
419                    $dumper->describeValue($compare) . "]";
420        } else {
421            return $this->_describeTextMatch($this->_getSubstring(), $compare);
422        }
423    }
424}
425
426/**
427 *    Test case for testing of web pages. Allows
428 *    fetching of pages, parsing of HTML and
429 *    submitting forms.
430 *    @package SimpleTest
431 *    @subpackage WebTester
432 */
433class WebTestCase extends SimpleTestCase {
434    var $_browser;
435    var $_ignore_errors = false;
436   
437    /**
438     *    Creates an empty test case. Should be subclassed
439     *    with test methods for a functional test case.
440     *    @param string $label     Name of test case. Will use
441     *                             the class name if none specified.
442     *    @access public
443     */
444    function WebTestCase($label = false) {
445        $this->SimpleTestCase($label);
446    }
447   
448    /**
449     *    Announces the start of the test.
450     *    @param string $method    Test method just started.
451     *    @access public
452     */
453    function before($method) {
454        parent::before($method);
455        $this->setBrowser($this->createBrowser());
456    }
457
458    /**
459     *    Announces the end of the test. Includes private clean up.
460     *    @param string $method    Test method just finished.
461     *    @access public
462     */
463    function after($method) {
464        $this->unsetBrowser();
465        parent::after($method);
466    }
467   
468    /**
469     *    Gets a current browser reference for setting
470     *    special expectations or for detailed
471     *    examination of page fetches.
472     *    @return SimpleBrowser     Current test browser object.
473     *    @access public
474     */
475    function &getBrowser() {
476        return $this->_browser;
477    }
478   
479    /**
480     *    Gets a current browser reference for setting
481     *    special expectations or for detailed
482     *    examination of page fetches.
483     *    @param SimpleBrowser $browser    New test browser object.
484     *    @access public
485     */
486    function setBrowser(&$browser) {
487        return $this->_browser = &$browser;
488    }
489       
490    /**
491     *    Clears the current browser reference to help the
492     *    PHP garbage collector.
493     *    @access public
494     */
495    function unsetBrowser() {
496        unset($this->_browser);
497    }
498   
499    /**
500     *    Creates a new default web browser object.
501     *    Will be cleared at the end of the test method.
502     *    @return TestBrowser           New browser.
503     *    @access public
504     */
505    function &createBrowser() {
506        $browser = &new SimpleBrowser();
507        return $browser;
508    }
509   
510    /**
511     *    Gets the last response error.
512     *    @return string    Last low level HTTP error.
513     *    @access public
514     */
515    function getTransportError() {
516        return $this->_browser->getTransportError();
517    }
518       
519    /**
520     *    Accessor for the currently selected URL.
521     *    @return string        Current location or false if
522     *                          no page yet fetched.
523     *    @access public
524     */
525    function getUrl() {
526        return $this->_browser->getUrl();
527    }
528   
529    /**
530     *    Dumps the current request for debugging.
531     *    @access public
532     */
533    function showRequest() {
534        $this->dump($this->_browser->getRequest());
535    }
536   
537    /**
538     *    Dumps the current HTTP headers for debugging.
539     *    @access public
540     */
541    function showHeaders() {
542        $this->dump($this->_browser->getHeaders());
543    }
544   
545    /**
546     *    Dumps the current HTML source for debugging.
547     *    @access public
548     */
549    function showSource() {
550        $this->dump($this->_browser->getContent());
551    }
552   
553    /**
554     *    Dumps the visible text only for debugging.
555     *    @access public
556     */
557    function showText() {
558        $this->dump(wordwrap($this->_browser->getContentAsText(), 80));
559    }
560   
561    /**
562     *    Simulates the closing and reopening of the browser.
563     *    Temporary cookies will be discarded and timed
564     *    cookies will be expired if later than the
565     *    specified time.
566     *    @param string/integer $date Time when session restarted.
567     *                                If ommitted then all persistent
568     *                                cookies are kept. Time is either
569     *                                Cookie format string or timestamp.
570     *    @access public
571     */
572    function restart($date = false) {
573        if ($date === false) {
574            $date = time();
575        }
576        $this->_browser->restart($date);
577    }
578   
579    /**
580     *    Moves cookie expiry times back into the past.
581     *    Useful for testing timeouts and expiries.
582     *    @param integer $interval    Amount to age in seconds.
583     *    @access public
584     */
585    function ageCookies($interval) {
586        $this->_browser->ageCookies($interval);
587    }
588   
589    /**
590     *    Disables frames support. Frames will not be fetched
591     *    and the frameset page will be used instead.
592     *    @access public
593     */
594    function ignoreFrames() {
595        $this->_browser->ignoreFrames();
596    }
597   
598    /**
599     *    Switches off cookie sending and recieving.
600     *    @access public
601     */
602    function ignoreCookies() {
603        $this->_browser->ignoreCookies();
604    }
605   
606    /**
607     *    Skips errors for the next request only. You might
608     *    want to confirm that a page is unreachable for
609     *    example.
610     *    @access public
611     */
612    function ignoreErrors() {
613        $this->_ignore_errors = true;
614    }
615   
616    /**
617     *    Issues a fail if there is a transport error anywhere
618     *    in the current frameset. Only one such error is
619     *    reported.
620     *    @param string/boolean $result   HTML or failure.
621     *    @return string/boolean $result  Passes through result.
622     *    @access private
623     */
624    function _failOnError($result) {
625        if (! $this->_ignore_errors) {
626            if ($error = $this->_browser->getTransportError()) {
627                $this->fail($error);
628            }
629        }
630        $this->_ignore_errors = false;
631        return $result;
632    }
633
634    /**
635     *    Adds a header to every fetch.
636     *    @param string $header       Header line to add to every
637     *                                request until cleared.
638     *    @access public
639     */
640    function addHeader($header) {
641        $this->_browser->addHeader($header);
642    }
643   
644    /**
645     *    Sets the maximum number of redirects before
646     *    the web page is loaded regardless.
647     *    @param integer $max        Maximum hops.
648     *    @access public
649     */
650    function setMaximumRedirects($max) {
651        if (! $this->_browser) {
652            trigger_error(
653                    'Can only set maximum redirects in a test method, setUp() or tearDown()');
654        }
655        $this->_browser->setMaximumRedirects($max);
656    }
657   
658    /**
659     *    Sets the socket timeout for opening a connection and
660     *    receiving at least one byte of information.
661     *    @param integer $timeout      Maximum time in seconds.
662     *    @access public
663     */
664    function setConnectionTimeout($timeout) {
665        $this->_browser->setConnectionTimeout($timeout);
666    }
667   
668    /**
669     *    Sets proxy to use on all requests for when
670     *    testing from behind a firewall. Set URL
671     *    to false to disable.
672     *    @param string $proxy        Proxy URL.
673     *    @param string $username     Proxy username for authentication.
674     *    @param string $password     Proxy password for authentication.
675     *    @access public
676     */
677    function useProxy($proxy, $username = false, $password = false) {
678        $this->_browser->useProxy($proxy, $username, $password);
679    }
680   
681    /**
682     *    Fetches a page into the page buffer. If
683     *    there is no base for the URL then the
684     *    current base URL is used. After the fetch
685     *    the base URL reflects the new location.
686     *    @param string $url          URL to fetch.
687     *    @param hash $parameters     Optional additional GET data.
688     *    @return boolean/string      Raw page on success.
689     *    @access public
690     */
691    function get($url, $parameters = false) {
692        return $this->_failOnError($this->_browser->get($url, $parameters));
693    }
694   
695    /**
696     *    Fetches a page by POST into the page buffer.
697     *    If there is no base for the URL then the
698     *    current base URL is used. After the fetch
699     *    the base URL reflects the new location.
700     *    @param string $url          URL to fetch.
701     *    @param hash $parameters     Optional additional GET data.
702     *    @return boolean/string      Raw page on success.
703     *    @access public
704     */
705    function post($url, $parameters = false) {
706        return $this->_failOnError($this->_browser->post($url, $parameters));
707    }
708   
709    /**
710     *    Does a HTTP HEAD fetch, fetching only the page
711     *    headers. The current base URL is unchanged by this.
712     *    @param string $url          URL to fetch.
713     *    @param hash $parameters     Optional additional GET data.
714     *    @return boolean             True on success.
715     *    @access public
716     */
717    function head($url, $parameters = false) {
718        return $this->_failOnError($this->_browser->head($url, $parameters));
719    }
720   
721    /**
722     *    Equivalent to hitting the retry button on the
723     *    browser. Will attempt to repeat the page fetch.
724     *    @return boolean     True if fetch succeeded.
725     *    @access public
726     */
727    function retry() {
728        return $this->_failOnError($this->_browser->retry());
729    }
730   
731    /**
732     *    Equivalent to hitting the back button on the
733     *    browser.
734     *    @return boolean     True if history entry and
735     *                        fetch succeeded.
736     *    @access public
737     */
738    function back() {
739        return $this->_failOnError($this->_browser->back());
740    }
741   
742    /**
743     *    Equivalent to hitting the forward button on the
744     *    browser.
745     *    @return boolean     True if history entry and
746     *                        fetch succeeded.
747     *    @access public
748     */
749    function forward() {
750        return $this->_failOnError($this->_browser->forward());
751    }
752   
753    /**
754     *    Retries a request after setting the authentication
755     *    for the current realm.
756     *    @param string $username    Username for realm.
757     *    @param string $password    Password for realm.
758     *    @return boolean/string     HTML on successful fetch. Note
759     *                               that authentication may still have
760     *                               failed.
761     *    @access public
762     */
763    function authenticate($username, $password) {
764        return $this->_failOnError(
765                $this->_browser->authenticate($username, $password));
766    }
767   
768    /**
769     *    Gets the cookie value for the current browser context.
770     *    @param string $name          Name of cookie.
771     *    @return string               Value of cookie or false if unset.
772     *    @access public
773     */
774    function getCookie($name) {
775        return $this->_browser->getCurrentCookieValue($name);
776    }
777   
778    /**
779     *    Sets a cookie in the current browser.
780     *    @param string $name          Name of cookie.
781     *    @param string $value         Cookie value.
782     *    @param string $host          Host upon which the cookie is valid.
783     *    @param string $path          Cookie path if not host wide.
784     *    @param string $expiry        Expiry date.
785     *    @access public
786     */
787    function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
788        $this->_browser->setCookie($name, $value, $host, $path, $expiry);
789    }
790   
791    /**
792     *    Accessor for current frame focus. Will be
793     *    false if no frame has focus.
794     *    @return integer/string/boolean    Label if any, otherwise
795     *                                      the position in the frameset
796     *                                      or false if none.
797     *    @access public
798     */
799    function getFrameFocus() {
800        return $this->_browser->getFrameFocus();
801    }
802   
803    /**
804     *    Sets the focus by index. The integer index starts from 1.
805     *    @param integer $choice    Chosen frame.
806     *    @return boolean           True if frame exists.
807     *    @access public
808     */
809    function setFrameFocusByIndex($choice) {
810        return $this->_browser->setFrameFocusByIndex($choice);
811    }
812   
813    /**
814     *    Sets the focus by name.
815     *    @param string $name    Chosen frame.
816     *    @return boolean        True if frame exists.
817     *    @access public
818     */
819    function setFrameFocus($name) {
820        return $this->_browser->setFrameFocus($name);
821    }
822   
823    /**
824     *    Clears the frame focus. All frames will be searched
825     *    for content.
826     *    @access public
827     */
828    function clearFrameFocus() {
829        return $this->_browser->clearFrameFocus();
830    }
831   
832    /**
833     *    Clicks a visible text item. Will first try buttons,
834     *    then links and then images.
835     *    @param string $label        Visible text or alt text.
836     *    @return string/boolean      Raw page or false.
837     *    @access public
838     */
839    function click($label) {
840        return $this->_failOnError($this->_browser->click($label));
841    }
842   
843    /**
844     *    Checks for a click target.
845     *    @param string $label        Visible text or alt text.
846     *    @return boolean             True if click target.
847     *    @access public
848     */   
849    function assertClickable($label, $message = '%s') {
850        return $this->assertTrue(
851                $this->_browser->isClickable($label),
852                sprintf($message, "Click target [$label] should exist"));
853    }
854   
855    /**
856     *    Clicks the submit button by label. The owning
857     *    form will be submitted by this.
858     *    @param string $label    Button label. An unlabeled
859     *                            button can be triggered by 'Submit'.
860     *    @param hash $additional Additional form values.
861     *    @return boolean/string  Page on success, else false.
862     *    @access public
863     */
864    function clickSubmit($label = 'Submit', $additional = false) {
865        return $this->_failOnError(
866                $this->_browser->clickSubmit($label, $additional));
867    }
868   
869    /**
870     *    Clicks the submit button by name attribute. The owning
871     *    form will be submitted by this.
872     *    @param string $name     Name attribute of button.
873     *    @param hash $additional Additional form values.
874     *    @return boolean/string  Page on success.
875     *    @access public
876     */
877    function clickSubmitByName($name, $additional = false) {
878        return $this->_failOnError(
879                $this->_browser->clickSubmitByName($name, $additional));
880    }
881   
882    /**
883     *    Clicks the submit button by ID attribute. The owning
884     *    form will be submitted by this.
885     *    @param string $id       ID attribute of button.
886     *    @param hash $additional Additional form values.
887     *    @return boolean/string  Page on success.
888     *    @access public
889     */
890    function clickSubmitById($id, $additional = false) {
891        return $this->_failOnError(
892                $this->_browser->clickSubmitById($id, $additional));
893    }
894   
895    /**
896     *    Checks for a valid button label.
897     *    @param string $label        Visible text.
898     *    @return boolean             True if click target.
899     *    @access public
900     */   
901    function assertSubmit($label, $message = '%s') {
902        return $this->assertTrue(
903                $this->_browser->isSubmit($label),
904                sprintf($message, "Submit button [$label] should exist"));
905    }
906   
907    /**
908     *    Clicks the submit image by some kind of label. Usually
909     *    the alt tag or the nearest equivalent. The owning
910     *    form will be submitted by this. Clicking outside of
911     *    the boundary of the coordinates will result in
912     *    a failure.
913     *    @param string $label    Alt attribute of button.
914     *    @param integer $x       X-coordinate of imaginary click.
915     *    @param integer $y       Y-coordinate of imaginary click.
916     *    @param hash $additional Additional form values.
917     *    @return boolean/string  Page on success.
918     *    @access public
919     */
920    function clickImage($label, $x = 1, $y = 1, $additional = false) {
921        return $this->_failOnError(
922                $this->_browser->clickImage($label, $x, $y, $additional));
923    }
924   
925    /**
926     *    Clicks the submit image by the name. Usually
927     *    the alt tag or the nearest equivalent. The owning
928     *    form will be submitted by this. Clicking outside of
929     *    the boundary of the coordinates will result in
930     *    a failure.
931     *    @param string $name     Name attribute of button.
932     *    @param integer $x       X-coordinate of imaginary click.
933     *    @param integer $y       Y-coordinate of imaginary click.
934     *    @param hash $additional Additional form values.
935     *    @return boolean/string  Page on success.
936     *    @access public
937     */
938    function clickImageByName($name, $x = 1, $y = 1, $additional = false) {
939        return $this->_failOnError(
940                $this->_browser->clickImageByName($name, $x, $y, $additional));
941    }
942   
943    /**
944     *    Clicks the submit image by ID attribute. The owning
945     *    form will be submitted by this. Clicking outside of
946     *    the boundary of the coordinates will result in
947     *    a failure.
948     *    @param integer/string $id   ID attribute of button.
949     *    @param integer $x           X-coordinate of imaginary click.
950     *    @param integer $y           Y-coordinate of imaginary click.
951     *    @param hash $additional     Additional form values.
952     *    @return boolean/string      Page on success.
953     *    @access public
954     */
955    function clickImageById($id, $x = 1, $y = 1, $additional = false) {
956        return $this->_failOnError(
957                $this->_browser->clickImageById($id, $x, $y, $additional));
958    }
959   
960    /**
961     *    Checks for a valid image with atht alt text or title.
962     *    @param string $label        Visible text.
963     *    @return boolean             True if click target.
964     *    @access public
965     */   
966    function assertImage($label, $message = '%s') {
967        return $this->assertTrue(
968                $this->_browser->isImage($label),
969                sprintf($message, "Image with text [$label] should exist"));
970    }
971   
972    /**
973     *    Submits a form by the ID.
974     *    @param string $id       Form ID. No button information
975     *                            is submitted this way.
976     *    @return boolean/string  Page on success.
977     *    @access public
978     */
979    function submitFormById($id) {
980        return $this->_failOnError($this->_browser->submitFormById($id));
981    }
982   
983    /**
984     *    Follows a link by name. Will click the first link
985     *    found with this link text by default, or a later
986     *    one if an index is given. Match is case insensitive
987     *    with normalised space.
988     *    @param string $label     Text between the anchor tags.
989     *    @param integer $index    Link position counting from zero.
990     *    @return boolean/string   Page on success.
991     *    @access public
992     */
993    function clickLink($label, $index = 0) {
994        return $this->_failOnError($this->_browser->clickLink($label, $index));
995    }
996   
997    /**
998     *    Follows a link by id attribute.
999     *    @param string $id        ID attribute value.
1000     *    @return boolean/string   Page on success.
1001     *    @access public
1002     */
1003    function clickLinkById($id) {
1004        return $this->_failOnError($this->_browser->clickLinkById($id));
1005    }
1006   
1007    /**
1008     *    Tests for the presence of a link label. Match is
1009     *    case insensitive with normalised space.
1010     *    @param string $label     Text between the anchor tags.
1011     *    @param mixed $expected   Expected URL or expectation object.
1012     *    @param string $message   Message to display. Default
1013     *                             can be embedded with %s.
1014     *    @return boolean          True if link present.
1015     *    @access public
1016     */
1017    function assertLink($label, $expected = true, $message = '%s') {
1018        $url = $this->_browser->getLink($label);
1019        if ($expected === true || ($expected !== true && $url === false)) {
1020            return $this->assertTrue($url !== false, sprintf($message, "Link [$label] should exist"));
1021        }
1022        if (! SimpleExpectation::isExpectation($expected)) {
1023            $expected = new IdenticalExpectation($expected);
1024        }
1025        return $this->assert($expected, $url->asString(), sprintf($message, "Link [$label] should match"));
1026    }
1027
1028    /**
1029     *    Tests for the non-presence of a link label. Match is
1030     *    case insensitive with normalised space.
1031     *    @param string/integer $label    Text between the anchor tags
1032     *                                    or ID attribute.
1033     *    @param string $message          Message to display. Default
1034     *                                    can be embedded with %s.
1035     *    @return boolean                 True if link missing.
1036     *    @access public
1037     */
1038    function assertNoLink($label, $message = '%s') {
1039        return $this->assertTrue(
1040                $this->_browser->getLink($label) === false,
1041                sprintf($message, "Link [$label] should not exist"));
1042    }
1043   
1044    /**
1045     *    Tests for the presence of a link id attribute.
1046     *    @param string $id        Id attribute value.
1047     *    @param mixed $expected   Expected URL or expectation object.
1048     *    @param string $message   Message to display. Default
1049     *                             can be embedded with %s.
1050     *    @return boolean          True if link present.
1051     *    @access public
1052     */
1053    function assertLinkById($id, $expected = true, $message = '%s') {
1054        $url = $this->_browser->getLinkById($id);
1055        if ($expected === true) {
1056            return $this->assertTrue($url !== false, sprintf($message, "Link ID [$id] should exist"));
1057        }
1058        if (! SimpleExpectation::isExpectation($expected)) {
1059            $expected = new IdenticalExpectation($expected);
1060        }
1061        return $this->assert($expected, $url->asString(), sprintf($message, "Link ID [$id] should match"));
1062    }
1063
1064    /**
1065     *    Tests for the non-presence of a link label. Match is
1066     *    case insensitive with normalised space.
1067     *    @param string $id        Id attribute value.
1068     *    @param string $message   Message to display. Default
1069     *                             can be embedded with %s.
1070     *    @return boolean          True if link missing.
1071     *    @access public
1072     */
1073    function assertNoLinkById($id, $message = '%s') {
1074        return $this->assertTrue(
1075                $this->_browser->getLinkById($id) === false,
1076                sprintf($message, "Link ID [$id] should not exist"));
1077    }
1078   
1079    /**
1080     *    Sets all form fields with that label, or name if there
1081     *    is no label attached.
1082     *    @param string $name    Name of field in forms.
1083     *    @param string $value   New value of field.
1084     *    @return boolean        True if field exists, otherwise false.
1085     *    @access public
1086     */
1087    function setField($label, $value, $position=false) {
1088        return $this->_browser->setField($label, $value, $position);
1089    }
1090   
1091    /**
1092     *    Sets all form fields with that name.
1093     *    @param string $name    Name of field in forms.
1094     *    @param string $value   New value of field.
1095     *    @return boolean        True if field exists, otherwise false.
1096     *    @access public
1097     */
1098    function setFieldByName($name, $value, $position=false) {
1099        return $this->_browser->setFieldByName($name, $value, $position);
1100    }
1101       
1102    /**
1103     *    Sets all form fields with that id.
1104     *    @param string/integer $id   Id of field in forms.
1105     *    @param string $value        New value of field.
1106     *    @return boolean             True if field exists, otherwise false.
1107     *    @access public
1108     */
1109    function setFieldById($id, $value) {
1110        return $this->_browser->setFieldById($id, $value);
1111    }
1112   
1113    /**
1114     *    Confirms that the form element is currently set
1115     *    to the expected value. A missing form will always
1116     *    fail. If no value is given then only the existence
1117     *    of the field is checked.
1118     *    @param string $name       Name of field in forms.
1119     *    @param mixed $expected    Expected string/array value or
1120     *                              false for unset fields.
1121     *    @param string $message    Message to display. Default
1122     *                              can be embedded with %s.
1123     *    @return boolean           True if pass.
1124     *    @access public
1125     */
1126    function assertField($label, $expected = true, $message = '%s') {
1127        $value = $this->_browser->getField($label);
1128        return $this->_assertFieldValue($label, $value, $expected, $message);
1129    }
1130   
1131    /**
1132     *    Confirms that the form element is currently set
1133     *    to the expected value. A missing form element will always
1134     *    fail. If no value is given then only the existence
1135     *    of the field is checked.
1136     *    @param string $name       Name of field in forms.
1137     *    @param mixed $expected    Expected string/array value or
1138     *                              false for unset fields.
1139     *    @param string $message    Message to display. Default
1140     *                              can be embedded with %s.
1141     *    @return boolean           True if pass.
1142     *    @access public
1143     */
1144    function assertFieldByName($name, $expected = true, $message = '%s') {
1145        $value = $this->_browser->getFieldByName($name);
1146        return $this->_assertFieldValue($name, $value, $expected, $message);
1147    }
1148       
1149    /**
1150     *    Confirms that the form element is currently set
1151     *    to the expected value. A missing form will always
1152     *    fail. If no ID is given then only the existence
1153     *    of the field is checked.
1154     *    @param string/integer $id  Name of field in forms.
1155     *    @param mixed $expected     Expected string/array value or
1156     *                               false for unset fields.
1157     *    @param string $message     Message to display. Default
1158     *                               can be embedded with %s.
1159     *    @return boolean            True if pass.
1160     *    @access public
1161     */
1162    function assertFieldById($id, $expected = true, $message = '%s') {
1163        $value = $this->_browser->getFieldById($id);
1164        return $this->_assertFieldValue($id, $value, $expected, $message);
1165    }
1166   
1167    /**
1168     *    Tests the field value against the expectation.
1169     *    @param string $identifier      Name, ID or label.
1170     *    @param mixed $value            Current field value.
1171     *    @param mixed $expected         Expected value to match.
1172     *    @param string $message         Failure message.
1173     *    @return boolean                True if pass
1174     *    @access protected
1175     */
1176    function _assertFieldValue($identifier, $value, $expected, $message) {
1177        if ($expected === true) {
1178            return $this->assertTrue(
1179                    isset($value),
1180                    sprintf($message, "Field [$identifier] should exist"));
1181        }
1182        if (! SimpleExpectation::isExpectation($expected)) {
1183            $identifier = str_replace('%', '%%', $identifier);
1184            $expected = new FieldExpectation(
1185                    $expected,
1186                    "Field [$identifier] should match with [%s]");
1187        }
1188        return $this->assert($expected, $value, $message);
1189    }
1190   
1191    /**
1192     *    Checks the response code against a list
1193     *    of possible values.
1194     *    @param array $responses    Possible responses for a pass.
1195     *    @param string $message     Message to display. Default
1196     *                               can be embedded with %s.
1197     *    @return boolean            True if pass.
1198     *    @access public
1199     */
1200    function assertResponse($responses, $message = '%s') {
1201        $responses = (is_array($responses) ? $responses : array($responses));
1202        $code = $this->_browser->getResponseCode();
1203        $message = sprintf($message, "Expecting response in [" .
1204                implode(", ", $responses) . "] got [$code]");
1205        return $this->assertTrue(in_array($code, $responses), $message);
1206    }
1207   
1208    /**
1209     *    Checks the mime type against a list
1210     *    of possible values.
1211     *    @param array $types      Possible mime types for a pass.
1212     *    @param string $message   Message to display.
1213     *    @return boolean          True if pass.
1214     *    @access public
1215     */
1216    function assertMime($types, $message = '%s') {
1217        $types = (is_array($types) ? $types : array($types));
1218        $type = $this->_browser->getMimeType();
1219        $message = sprintf($message, "Expecting mime type in [" .
1220                implode(", ", $types) . "] got [$type]");
1221        return $this->assertTrue(in_array($type, $types), $message);
1222    }
1223   
1224    /**
1225     *    Attempt to match the authentication type within
1226     *    the security realm we are currently matching.
1227     *    @param string $authentication   Usually basic.
1228     *    @param string $message          Message to display.
1229     *    @return boolean                 True if pass.
1230     *    @access public
1231     */
1232    function assertAuthentication($authentication = false, $message = '%s') {
1233        if (! $authentication) {
1234            $message = sprintf($message, "Expected any authentication type, got [" .
1235                    $this->_browser->getAuthentication() . "]");
1236            return $this->assertTrue(
1237                    $this->_browser->getAuthentication(),
1238                    $message);
1239        } else {
1240            $message = sprintf($message, "Expected authentication [$authentication] got [" .
1241                    $this->_browser->getAuthentication() . "]");
1242            return $this->assertTrue(
1243                    strtolower($this->_browser->getAuthentication()) == strtolower($authentication),
1244                    $message);
1245        }
1246    }
1247   
1248    /**
1249     *    Checks that no authentication is necessary to view
1250     *    the desired page.
1251     *    @param string $message     Message to display.
1252     *    @return boolean            True if pass.
1253     *    @access public
1254     */
1255    function assertNoAuthentication($message = '%s') {
1256        $message = sprintf($message, "Expected no authentication type, got [" .
1257                $this->_browser->getAuthentication() . "]");
1258        return $this->assertFalse($this->_browser->getAuthentication(), $message);
1259    }
1260   
1261    /**
1262     *    Attempts to match the current security realm.
1263     *    @param string $realm     Name of security realm.
1264     *    @param string $message   Message to display.
1265     *    @return boolean          True if pass.
1266     *    @access public
1267     */
1268    function assertRealm($realm, $message = '%s') {
1269        if (! SimpleExpectation::isExpectation($realm)) {
1270            $realm = new EqualExpectation($realm);
1271        }
1272        return $this->assert(
1273                $realm,
1274                $this->_browser->getRealm(),
1275                "Expected realm -> $message");
1276    }
1277   
1278    /**
1279     *    Checks each header line for the required value. If no
1280     *    value is given then only an existence check is made.
1281     *    @param string $header    Case insensitive header name.
1282     *    @param mixed $value      Case sensitive trimmed string to
1283     *                             match against. An expectation object
1284     *                             can be used for pattern matching.
1285     *    @return boolean          True if pass.
1286     *    @access public
1287     */
1288    function assertHeader($header, $value = false, $message = '%s') {
1289        return $this->assert(
1290                new HttpHeaderExpectation($header, $value),
1291                $this->_browser->getHeaders(),
1292                $message);
1293    }
1294       
1295    /**
1296     *    @deprecated
1297     */
1298    function assertHeaderPattern($header, $pattern, $message = '%s') {
1299        return $this->assert(
1300                new HttpHeaderExpectation($header, new PatternExpectation($pattern)),
1301                $this->_browser->getHeaders(),
1302                $message);
1303    }
1304
1305    /**
1306     *    Confirms that the header type has not been received.
1307     *    Only the landing page is checked. If you want to check
1308     *    redirect pages, then you should limit redirects so
1309     *    as to capture the page you want.
1310     *    @param string $header    Case insensitive header name.
1311     *    @return boolean          True if pass.
1312     *    @access public
1313     */
1314    function assertNoHeader($header, $message = '%s') {
1315        return $this->assert(
1316                new NoHttpHeaderExpectation($header),
1317                $this->_browser->getHeaders(),
1318                $message);
1319    }
1320       
1321    /**
1322     *    @deprecated
1323     */
1324    function assertNoUnwantedHeader($header, $message = '%s') {
1325        return $this->assertNoHeader($header, $message);
1326    }
1327   
1328    /**
1329     *    Tests the text between the title tags.
1330     *    @param string/SimpleExpectation $title    Expected title.
1331     *    @param string $message                    Message to display.
1332     *    @return boolean                           True if pass.
1333     *    @access public
1334     */
1335    function assertTitle($title = false, $message = '%s') {
1336        if (! SimpleExpectation::isExpectation($title)) {
1337            $title = new EqualExpectation($title);
1338        }
1339        return $this->assert($title, $this->_browser->getTitle(), $message);
1340    }
1341   
1342    /**
1343     *    Will trigger a pass if the text is found in the plain
1344     *    text form of the page.
1345     *    @param string $text       Text to look for.
1346     *    @param string $message    Message to display.
1347     *    @return boolean           True if pass.
1348     *    @access public
1349     */
1350    function assertText($text, $message = '%s') {
1351        return $this->assert(
1352                new TextExpectation($text),
1353                $this->_browser->getContentAsText(),
1354                $message);
1355    }
1356   
1357    /**
1358     *    @deprecated
1359     */
1360    function assertWantedText($text, $message = '%s') {
1361        return $this->assertText($text, $message);
1362    }
1363   
1364    /**
1365     *    Will trigger a pass if the text is not found in the plain
1366     *    text form of the page.
1367     *    @param string $text       Text to look for.
1368     *    @param string $message    Message to display.
1369     *    @return boolean           True if pass.
1370     *    @access public
1371     */
1372    function assertNoText($text, $message = '%s') {
1373        return $this->assert(
1374                new NoTextExpectation($text),
1375                $this->_browser->getContentAsText(),
1376                $message);
1377    }
1378   
1379    /**
1380     *    @deprecated
1381     */
1382    function assertNoUnwantedText($text, $message = '%s') {
1383        return $this->assertNoText($text, $message);
1384    }
1385   
1386    /**
1387     *    Will trigger a pass if the Perl regex pattern
1388     *    is found in the raw content.
1389     *    @param string $pattern    Perl regex to look for including
1390     *                              the regex delimiters.
1391     *    @param string $message    Message to display.
1392     *    @return boolean           True if pass.
1393     *    @access public
1394     */
1395    function assertPattern($pattern, $message = '%s') {
1396        return $this->assert(
1397                new PatternExpectation($pattern),
1398                $this->_browser->getContent(),
1399                $message);
1400    }
1401   
1402    /**
1403     *    @deprecated
1404     */
1405    function assertWantedPattern($pattern, $message = '%s') {
1406        return $this->assertPattern($pattern, $message);
1407    }
1408   
1409    /**
1410     *    Will trigger a pass if the perl regex pattern
1411     *    is not present in raw content.
1412     *    @param string $pattern    Perl regex to look for including
1413     *                              the regex delimiters.
1414     *    @param string $message    Message to display.
1415     *    @return boolean           True if pass.
1416     *    @access public
1417     */
1418    function assertNoPattern($pattern, $message = '%s') {
1419        return $this->assert(
1420                new NoPatternExpectation($pattern),
1421                $this->_browser->getContent(),
1422                $message);
1423    }
1424   
1425    /**
1426     *    @deprecated
1427     */
1428    function assertNoUnwantedPattern($pattern, $message = '%s') {
1429        return $this->assertNoPattern($pattern, $message);
1430    }
1431   
1432    /**
1433     *    Checks that a cookie is set for the current page
1434     *    and optionally checks the value.
1435     *    @param string $name        Name of cookie to test.
1436     *    @param string $expected    Expected value as a string or
1437     *                               false if any value will do.
1438     *    @param string $message     Message to display.
1439     *    @return boolean            True if pass.
1440     *    @access public
1441     */
1442    function assertCookie($name, $expected = false, $message = '%s') {
1443        $value = $this->getCookie($name);
1444        if (! $expected) {
1445            return $this->assertTrue(
1446                    $value,
1447                    sprintf($message, "Expecting cookie [$name]"));
1448        }
1449        if (! SimpleExpectation::isExpectation($expected)) {
1450            $expected = new EqualExpectation($expected);
1451        }
1452        return $this->assert($expected, $value, "Expecting cookie [$name] -> $message");
1453    }
1454   
1455    /**
1456     *    Checks that no cookie is present or that it has
1457     *    been successfully cleared.
1458     *    @param string $name        Name of cookie to test.
1459     *    @param string $message     Message to display.
1460     *    @return boolean            True if pass.
1461     *    @access public
1462     */
1463    function assertNoCookie($name, $message = '%s') {
1464        return $this->assertTrue(
1465                $this->getCookie($name) === false,
1466                sprintf($message, "Not expecting cookie [$name]"));
1467    }
1468
1469    /**
1470     *    Called from within the test methods to register
1471     *    passes and failures.
1472     *    @param boolean $result    Pass on true.
1473     *    @param string $message    Message to display describing
1474     *                              the test state.
1475     *    @return boolean           True on pass
1476     *    @access public
1477     */
1478    function assertTrue($result, $message = false) {
1479        return $this->assert(new TrueExpectation(), $result, $message);
1480    }
1481
1482    /**
1483     *    Will be true on false and vice versa. False
1484     *    is the PHP definition of false, so that null,
1485     *    empty strings, zero and an empty array all count
1486     *    as false.
1487     *    @param boolean $result    Pass on false.
1488     *    @param string $message    Message to display.
1489     *    @return boolean           True on pass
1490     *    @access public
1491     */
1492    function assertFalse($result, $message = '%s') {
1493        return $this->assert(new FalseExpectation(), $result, $message);
1494    }
1495   
1496    /**
1497     *    Will trigger a pass if the two parameters have
1498     *    the same value only. Otherwise a fail. This
1499     *    is for testing hand extracted text, etc.
1500     *    @param mixed $first          Value to compare.
1501     *    @param mixed $second         Value to compare.
1502     *    @param string $message       Message to display.
1503     *    @return boolean              True on pass
1504     *    @access public
1505     */
1506    function assertEqual($first, $second, $message = '%s') {
1507        return $this->assert(
1508                new EqualExpectation($first),
1509                $second,
1510                $message);
1511    }
1512   
1513    /**
1514     *    Will trigger a pass if the two parameters have
1515     *    a different value. Otherwise a fail. This
1516     *    is for testing hand extracted text, etc.
1517     *    @param mixed $first           Value to compare.
1518     *    @param mixed $second          Value to compare.
1519     *    @param string $message        Message to display.
1520     *    @return boolean               True on pass
1521     *    @access public
1522     */
1523    function assertNotEqual($first, $second, $message = '%s') {
1524        return $this->assert(
1525                new NotEqualExpectation($first),
1526                $second,
1527                $message);
1528    }
1529
1530    /**
1531     *    Uses a stack trace to find the line of an assertion.
1532     *    @return string           Line number of first assert*
1533     *                             method embedded in format string.
1534     *    @access public
1535     */
1536    function getAssertionLine() {
1537        $trace = new SimpleStackTrace(array('assert', 'click', 'pass', 'fail'));
1538        return $trace->traceMethod();
1539    }
1540}
1541?>
Note: See TracBrowser for help on using the repository browser.