| [ 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 MockObjects 6 * @version $Id: mock_objects.php 5999 2007-06-18 13:13:08Z pachanga $ 7 */ 8 9 /**#@+ 10 * include SimpleTest files 11 */ 12 require_once(dirname(__FILE__) . '/expectation.php'); 13 require_once(dirname(__FILE__) . '/simpletest.php'); 14 require_once(dirname(__FILE__) . '/dumper.php'); 15 if (version_compare(phpversion(), '5') >= 0) { 16 require_once(dirname(__FILE__) . '/reflection_php5.php'); 17 } else { 18 require_once(dirname(__FILE__) . '/reflection_php4.php'); 19 } 20 /**#@-*/ 21 22 /** 23 * Default character simpletest will substitute for any value 24 */ 25 if (! defined('MOCK_ANYTHING')) { 26 define('MOCK_ANYTHING', '*'); 27 } 28 29 /** 30 * Parameter comparison assertion. 31 * @package SimpleTest 32 * @subpackage MockObjects 33 */ 34 class ParametersExpectation extends SimpleExpectation { 35 var $_expected; 36 37 /** 38 * Sets the expected parameter list. 39 * @param array $parameters Array of parameters including 40 * those that are wildcarded. 41 * If the value is not an array 42 * then it is considered to match any. 43 * @param string $message Customised message on failure. 44 * @access public 45 */ 46 function ParametersExpectation($expected = false, $message = '%s') { 47 $this->SimpleExpectation($message); 48 $this->_expected = $expected; 49 } 50 51 /** 52 * Tests the assertion. True if correct. 53 * @param array $parameters Comparison values. 54 * @return boolean True if correct. 55 * @access public 56 */ 57 function test($parameters) { 58 if (! is_array($this->_expected)) { 59 return true; 60 } 61 if (count($this->_expected) != count($parameters)) { 62 return false; 63 } 64 for ($i = 0; $i < count($this->_expected); $i++) { 65 if (! $this->_testParameter($parameters[$i], $this->_expected[$i])) { 66 return false; 67 } 68 } 69 return true; 70 } 71 72 /** 73 * Tests an individual parameter. 74 * @param mixed $parameter Value to test. 75 * @param mixed $expected Comparison value. 76 * @return boolean True if expectation 77 * fulfilled. 78 * @access private 79 */ 80 function _testParameter($parameter, $expected) { 81 $comparison = $this->_coerceToExpectation($expected); 82 return $comparison->test($parameter); 83 } 84 85 /** 86 * Returns a human readable test message. 87 * @param array $comparison Incoming parameter list. 88 * @return string Description of success 89 * or failure. 90 * @access public 91 */ 92 function testMessage($parameters) { 93 if ($this->test($parameters)) { 94 return "Expectation of " . count($this->_expected) . 95 " arguments of [" . $this->_renderArguments($this->_expected) . 96 "] is correct"; 97 } else { 98 return $this->_describeDifference($this->_expected, $parameters); 99 } 100 } 101 102 /** 103 * Message to display if expectation differs from 104 * the parameters actually received. 105 * @param array $expected Expected parameters as list. 106 * @param array $parameters Actual parameters received. 107 * @return string Description of difference. 108 * @access private 109 */ 110 function _describeDifference($expected, $parameters) { 111 if (count($expected) != count($parameters)) { 112 return "Expected " . count($expected) . 113 " arguments of [" . $this->_renderArguments($expected) . 114 "] but got " . count($parameters) . 115 " arguments of [" . $this->_renderArguments($parameters) . "]"; 116 } 117 $messages = array(); 118 for ($i = 0; $i < count($expected); $i++) { 119 $comparison = $this->_coerceToExpectation($expected[$i]); 120 if (! $comparison->test($parameters[$i])) { 121 $messages[] = "parameter " . ($i + 1) . " with [" . 122 $comparison->overlayMessage($parameters[$i], $this->_getDumper()) . "]"; 123 } 124 } 125 return "Parameter expectation differs at " . implode(" and ", $messages); 126 } 127 128 /** 129 * Creates an identical expectation if the 130 * object/value is not already some type 131 * of expectation. 132 * @param mixed $expected Expected value. 133 * @return SimpleExpectation Expectation object. 134 * @access private 135 */ 136 function _coerceToExpectation($expected) { 137 if (SimpleExpectation::isExpectation($expected)) { 138 return $expected; 139 } 140 return new IdenticalExpectation($expected); 141 } 142 143 /** 144 * Renders the argument list as a string for 145 * messages. 146 * @param array $args Incoming arguments. 147 * @return string Simple description of type and value. 148 * @access private 149 */ 150 function _renderArguments($args) { 151 $descriptions = array(); 152 if (is_array($args)) { 153 foreach ($args as $arg) { 154 $dumper = &new SimpleDumper(); 155 $descriptions[] = $dumper->describeValue($arg); 156 } 157 } 158 return implode(', ', $descriptions); 159 } 160 } 161 162 /** 163 * Confirms that the number of calls on a method is as expected. 164 * @package SimpleTest 165 * @subpackage MockObjects 166 */ 167 class CallCountExpectation extends SimpleExpectation { 168 var $_method; 169 var $_count; 170 171 /** 172 * Stashes the method and expected count for later 173 * reporting. 174 * @param string $method Name of method to confirm against. 175 * @param integer $count Expected number of calls. 176 * @param string $message Custom error message. 177 */ 178 function CallCountExpectation($method, $count, $message = '%s') { 179 $this->_method = $method; 180 $this->_count = $count; 181 $this->SimpleExpectation($message); 182 } 183 184 /** 185 * Tests the assertion. True if correct. 186 * @param integer $compare Measured call count. 187 * @return boolean True if expected. 188 * @access public 189 */ 190 function test($compare) { 191 return ($this->_count == $compare); 192 } 193 194 /** 195 * Reports the comparison. 196 * @param integer $compare Measured call count. 197 * @return string Message to show. 198 * @access public 199 */ 200 function testMessage($compare) { 201 return 'Expected call count for [' . $this->_method . 202 '] was [' . $this->_count . 203 '] got [' . $compare . ']'; 204 } 205 } 206 207 /** 208 * Confirms that the number of calls on a method is as expected. 209 * @package SimpleTest 210 * @subpackage MockObjects 211 */ 212 class MinimumCallCountExpectation extends SimpleExpectation { 213 var $_method; 214 var $_count; 215 216 /** 217 * Stashes the method and expected count for later 218 * reporting. 219 * @param string $method Name of method to confirm against. 220 * @param integer $count Minimum number of calls. 221 * @param string $message Custom error message. 222 */ 223 function MinimumCallCountExpectation($method, $count, $message = '%s') { 224 $this->_method = $method; 225 $this->_count = $count; 226 $this->SimpleExpectation($message); 227 } 228 229 /** 230 * Tests the assertion. True if correct. 231 * @param integer $compare Measured call count. 232 * @return boolean True if enough. 233 * @access public 234 */ 235 function test($compare) { 236 return ($this->_count <= $compare); 237 } 238 239 /** 240 * Reports the comparison. 241 * @param integer $compare Measured call count. 242 * @return string Message to show. 243 * @access public 244 */ 245 function testMessage($compare) { 246 return 'Minimum call count for [' . $this->_method . 247 '] was [' . $this->_count . 248 '] got [' . $compare . ']'; 249 } 250 } 251 252 /** 253 * Confirms that the number of calls on a method is as expected. 254 * @package SimpleTest 255 * @subpackage MockObjects 256 */ 257 class MaximumCallCountExpectation extends SimpleExpectation { 258 var $_method; 259 var $_count; 260 261 /** 262 * Stashes the method and expected count for later 263 * reporting. 264 * @param string $method Name of method to confirm against. 265 * @param integer $count Minimum number of calls. 266 * @param string $message Custom error message. 267 */ 268 function MaximumCallCountExpectation($method, $count, $message = '%s') { 269 $this->_method = $method; 270 $this->_count = $count; 271 $this->SimpleExpectation($message); 272 } 273 274 /** 275 * Tests the assertion. True if correct. 276 * @param integer $compare Measured call count. 277 * @return boolean True if not over. 278 * @access public 279 */ 280 function test($compare) { 281 return ($this->_count >= $compare); 282 } 283 284 /** 285 * Reports the comparison. 286 * @param integer $compare Measured call count. 287 * @return string Message to show. 288 * @access public 289 */ 290 function testMessage($compare) { 291 return 'Maximum call count for [' . $this->_method . 292 '] was [' . $this->_count . 293 '] got [' . $compare . ']'; 294 } 295 } 296 297 /** 298 * Retrieves values and references by searching the 299 * parameter lists until a match is found. 300 * @package SimpleTest 301 * @subpackage MockObjects 302 */ 303 class CallMap { 304 var $_map; 305 306 /** 307 * Creates an empty call map. 308 * @access public 309 */ 310 function CallMap() { 311 $this->_map = array(); 312 } 313 314 /** 315 * Stashes a value against a method call. 316 * @param array $parameters Arguments including wildcards. 317 * @param mixed $value Value copied into the map. 318 * @access public 319 */ 320 function addValue($parameters, $value) { 321 $this->addReference($parameters, $value); 322 } 323 324 /** 325 * Stashes a reference against a method call. 326 * @param array $parameters Array of arguments (including wildcards). 327 * @param mixed $reference Array reference placed in the map. 328 * @access public 329 */ 330 function addReference($parameters, &$reference) { 331 $place = count($this->_map); 332 $this->_map[$place] = array(); 333 $this->_map[$place]["params"] = new ParametersExpectation($parameters); 334 $this->_map[$place]["content"] = &$reference; 335 } 336 337 /** 338 * Searches the call list for a matching parameter 339 * set. Returned by reference. 340 * @param array $parameters Parameters to search by 341 * without wildcards. 342 * @return object Object held in the first matching 343 * slot, otherwise null. 344 * @access public 345 */ 346 function &findFirstMatch($parameters) { 347 $slot = $this->_findFirstSlot($parameters); 348 if (!isset($slot)) { 349 $null = null; 350 return $null; 351 } 352 return $slot["content"]; 353 } 354 355 /** 356 * Searches the call list for a matching parameter 357 * set. True if successful. 358 * @param array $parameters Parameters to search by 359 * without wildcards. 360 * @return boolean True if a match is present. 361 * @access public 362 */ 363 function isMatch($parameters) { 364 return ($this->_findFirstSlot($parameters) != null); 365 } 366 367 /** 368 * Searches the map for a matching item. 369 * @param array $parameters Parameters to search by 370 * without wildcards. 371 * @return array Reference to slot or null. 372 * @access private 373 */ 374 function &_findFirstSlot($parameters) { 375 $count = count($this->_map); 376 for ($i = 0; $i < $count; $i++) { 377 if ($this->_map[$i]["params"]->test($parameters)) { 378 return $this->_map[$i]; 379 } 380 } 381 $null = null; 382 return $null; 383 } 384 } 385 386 /** 387 * An empty collection of methods that can have their 388 * return values set and expectations made of the 389 * calls upon them. The mock will assert the 390 * expectations against it's attached test case in 391 * addition to the server stub behaviour. 392 * @package SimpleTest 393 * @subpackage MockObjects 394 */ 395 class SimpleMock { 396 var $_wildcard = MOCK_ANYTHING; 397 var $_is_strict = true; 398 var $_returns; 399 var $_return_sequence; 400 var $_call_counts; 401 var $_expected_counts; 402 var $_max_counts; 403 var $_expected_args; 404 var $_expected_args_at; 405 406 /** 407 * Creates an empty return list and expectation list. 408 * All call counts are set to zero. 409 */ 410 function SimpleMock() { 411 $this->_returns = array(); 412 $this->_return_sequence = array(); 413 $this->_call_counts = array(); 414 $this->_expected_counts = array(); 415 $this->_max_counts = array(); 416 $this->_expected_args = array(); 417 $this->_expected_args_at = array(); 418 $test = &$this->_getCurrentTestCase(); 419 $test->tell($this); 420 } 421 422 /** 423 * Disables a name check when setting expectations. 424 * This hack is needed for the partial mocks. 425 * @access public 426 */ 427 function disableExpectationNameChecks() { 428 $this->_is_strict = false; 429 } 430 431 /** 432 * Finds currently running test. 433 * @return SimpeTestCase Current test case. 434 * @access protected 435 */ 436 function &_getCurrentTestCase() { 437 $context = &SimpleTest::getContext(); 438 return $context->getTest(); 439 } 440 441 /** 442 * Die if bad arguments array is passed 443 * @param mixed $args The arguments value to be checked. 444 * @param string $task Description of task attempt. 445 * @return boolean Valid arguments 446 * @access private 447 */ 448 function _checkArgumentsIsArray($args, $task) { 449 if (! is_array($args)) { 450 trigger_error( 451 "Cannot $task as \$args parameter is not an array", 452 E_USER_ERROR); 453 } 454 } 455 456 /** 457 * Triggers a PHP error if the method is not part 458 * of this object. 459 * @param string $method Name of method. 460 * @param string $task Description of task attempt. 461 * @access protected 462 */ 463 function _dieOnNoMethod($method, $task) { 464 if ($this->_is_strict && ! method_exists($this, $method)) { 465 trigger_error( 466 "Cannot $task as no $method}() in class " . get_class($this), 467 E_USER_ERROR); 468 } 469 } 470 471 /** 472 * Replaces wildcard matches with wildcard 473 * expectations in the argument list. 474 * @param array $args Raw argument list. 475 * @return array Argument list with 476 * expectations. 477 * @access private 478 */ 479 function _replaceWildcards($args) { 480 if ($args === false) { 481 return false; 482 } 483 for ($i = 0; $i < count($args); $i++) { 484 if ($args[$i] === $this->_wildcard) { 485 $args[$i] = new AnythingExpectation(); 486 } 487 } 488 return $args; 489 } 490 491 /** 492 * Adds one to the call count of a method. 493 * @param string $method Method called. 494 * @param array $args Arguments as an array. 495 * @access protected 496 */ 497 function _addCall($method, $args) { 498 if (!isset($this->_call_counts[$method])) { 499 $this->_call_counts[$method] = 0; 500 } 501 $this->_call_counts[$method]++; 502 } 503 504 /** 505 * Fetches the call count of a method so far. 506 * @param string $method Method name called. 507 * @return Number of calls so far. 508 * @access public 509 */ 510 function getCallCount($method) { 511 $this->_dieOnNoMethod($method, "get call count"); 512 $method = strtolower($method); 513 if (! isset($this->_call_counts[$method])) { 514 return 0; 515 } 516 return $this->_call_counts[$method]; 517 } 518 519 /** 520 * Sets a return for a parameter list that will 521 * be passed by value for all calls to this method. 522 * @param string $method Method name. 523 * @param mixed $value Result of call passed by value. 524 * @param array $args List of parameters to match 525 * including wildcards. 526 * @access public 527 */ 528 function setReturnValue($method, $value, $args = false) { 529 $this->_dieOnNoMethod($method, "set return value"); 530 $args = $this->_replaceWildcards($args); 531 $method = strtolower($method); 532 if (! isset($this->_returns[$method])) { 533 $this->_returns[$method] = new CallMap(); 534 } 535 $this->_returns[$method]->addValue($args, $value); 536 } 537 538 /** 539 * Sets a return for a parameter list that will 540 * be passed by value only when the required call count 541 * is reached. 542 * @param integer $timing Number of calls in the future 543 * to which the result applies. If 544 * not set then all calls will return 545 * the value. 546 * @param string $method Method name. 547 * @param mixed $value Result of call passed by value. 548 * @param array $args List of parameters to match 549 * including wildcards. 550 * @access public 551 */ 552 function setReturnValueAt($timing, $method, $value, $args = false) { 553 $this->_dieOnNoMethod($method, "set return value sequence"); 554 $args = $this->_replaceWildcards($args); 555 $method = strtolower($method); 556 if (! isset($this->_return_sequence[$method])) { 557 $this->