| [ Index ] |
PHP Cross Reference of Limb3 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Base include file for SimpleTest. 4 * @package SimpleTest 5 * @subpackage WebTester 6 * @version $Id: web_tester.php 5999 2007-06-18 13:13:08Z pachanga $ 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 /** 19 * Test for an HTML widget value match. 20 * @package SimpleTest 21 * @subpackage WebTester 22 */ 23 class 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 */ 134 class 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 */ 264 class 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 */ 310 class 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 */ 384 class 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 */ 433 class 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 } 59