| [ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * base include file for SimpleTest 4 * @package SimpleTest 5 * @subpackage MockFunctions 6 * @version $Id: mock_objects.php,v 1.86 2005/09/10 23:01:56 lastcraft Exp $ 7 */ 8 9 /** 10 * Generates a mock version of a function. 11 * Note that all public methods in this class should be called 12 * statically 13 * Note that you must call the restore method yourself, to remove 14 * a mock function implementation after associated tests are 15 * complete 16 * @package SimpleTest 17 * @subpackage MockFunctions 18 */ 19 class MockFunction { 20 21 /** 22 * Raises an error if you construct MockFunction 23 * @access private 24 */ 25 function MockFunction() { 26 trigger_error('MockFunction only provides static methods', 27 E_USER_ERROR); 28 } 29 30 /** 31 * Generates a mock function 32 * @param string $function Function name to mock 33 * @access public 34 * @return SimpleMockFunction 35 * @static 36 */ 37 function & generate($function) { 38 $mock = & MockFunction::_instance($function, TRUE); 39 $mock->deploy(); 40 return $mock; 41 } 42 43 /** 44 * Removes the mock function implementation and restores 45 * the real implementation (if one existed) 46 * @TODO Would be good to have this called automatically 47 * @param string $function Function name 48 * @access public 49 * @static 50 */ 51 function restore($function) { 52 $mock = & MockFunction::_instance($function); 53 $mock->restore(); 54 } 55 56 /** 57 * Fetch a singleton instance of SimpleMockFunction 58 * @param string $function Function name 59 * @param boolean $fresh Force a fresh instance 60 * @access private 61 * @static 62 */ 63 function &_instance($function, $fresh = FALSE) { 64 static $singleton = array(); 65 66 $function = strtolower($function); 67 68 if ( $fresh ) { 69 if ( isset($singleton[$function]) ) { 70 unset($singleton[$function]); 71 } 72 } 73 74 if ( !isset($singleton[$function]) ) { 75 // TODO: case sensitivity issues 76 $class = $function."MockFunction"; 77 MockFunction::_generateSubClass($class, $function); 78 $singleton[$function] = new $class($function); 79 } 80 81 return $singleton[$function]; 82 } 83 84 /** 85 * Required for strict mode and SimpleMock 86 * @TODO Should perhaps be placed in SimpleFunctionGenerator 87 * @param string $class subclass name 88 * @param string $method method name 89 * @access private 90 * @static 91 */ 92 function _generateSubClass($class, $method) { 93 if ( class_exists($class) ) { 94 return; 95 } 96 $code = "class $class extends SimpleMockFunction {\n"; 97 $code .= " function $method () {}\n"; 98 $code .= "}\n"; 99 eval($code); 100 } 101 102 /** 103 * Changes the default wildcard object. 104 * @param string $function Function name wildcard applies to 105 * @param mixed $wildcard Parameter matching wildcard. 106 * @access public 107 * @static 108 */ 109 function setWildcard($function, $wildcard) { 110 $mock = & MockFunction::_instance($function); 111 $mock->setWildcard($wildcard); 112 } 113 114 /** 115 * Fetches the call count of a function so far. 116 * @param string $function Function name called. 117 * @return Number of calls so far. 118 * @access public 119 * @static 120 */ 121 function getCallCount($function) { 122 $mock = & MockFunction::_instance($function); 123 return $mock->getCallCount($function); 124 } 125 126 /** 127 * Sets a return for a parameter list that will 128 * be passed by value for all calls to this function. 129 * @param string $function Function name. 130 * @param mixed $value Result of call passed by value. 131 * @param array $args List of parameters to match 132 * including wildcards. 133 * @access public 134 * @static 135 */ 136 function setReturnValue($function, $value, $args = false) { 137 $mock = & MockFunction::_instance($function); 138 $mock->setReturnValue($function, $value, $args); 139 } 140 141 /** 142 * Sets a return for a parameter list that will 143 * be passed by value only when the required call count 144 * is reached. 145 * @param integer $timing Number of calls in the future 146 * to which the result applies. If 147 * not set then all calls will return 148 * the value. 149 * @param string $function Function name. 150 * @param mixed $value Result of call passed by value. 151 * @param array $args List of parameters to match 152 * including wildcards. 153 * @access public 154 * @static 155 */ 156 function setReturnValueAt($timing, $function, $value, $args = false) { 157 $mock = & MockFunction::_instance($function); 158 $mock->setReturnValueAt($timing, $function, $value, $args); 159 } 160 161 /** 162 * Sets a return for a parameter list that will 163 * be passed by reference for all calls. 164 * @param string $function Function name. 165 * @param mixed $reference Result of the call will be this object. 166 * @param array $args List of parameters to match 167 * including wildcards. 168 * @access public 169 * @static 170 */ 171 function setReturnReference($function, &$reference, $args = false) { 172 $mock = & MockFunction::_instance($function); 173 $mock->setReturnReference($function, $reference, $args); 174 } 175 176 /** 177 * Sets a return for a parameter list that will 178 * be passed by value only when the required call count 179 * is reached. 180 * @param integer $timing Number of calls in the future 181 * to which the result applies. If 182 * not set then all calls will return 183 * the value. 184 * @param string $function Function name. 185 * @param mixed $reference Result of the call will be this object. 186 * @param array $args List of parameters to match 187 * including wildcards. 188 * @access public 189 * @static 190 */ 191 function setReturnReferenceAt($timing, $function, &$reference, $args = false) { 192 $mock = & MockFunction::_instance($function); 193 $mock->setReturnReferenceAt($timing, $function, $reference, $args); 194 } 195 196 /** 197 * Sets up an expected call with a set of 198 * expected parameters in that call. All 199 * calls will be compared to these expectations 200 * regardless of when the call is made. 201 * @param string $function Function call to test. 202 * @param array $args Expected parameters for the call 203 * including wildcards. 204 * @param string $message Overridden message. 205 * @access public 206 * @static 207 */ 208 function expectArguments($function, $args, $message = '%s') { 209 $mock = & MockFunction::_instance($function); 210 $mock->expectArguments($function, $args, $message); 211 } 212 213 /** 214 * Sets up an expected call with a set of 215 * expected parameters in that call. The 216 * expected call count will be adjusted if it 217 * is set too low to reach this call. 218 * @param integer $timing Number of calls in the future at 219 * which to test. Next call is 0. 220 * @param string $function Function call to test. 221 * @param array $args Expected parameters for the call 222 * including wildcards. 223 * @param string $message Overridden message. 224 * @access public 225 * @static 226 */ 227 function expectArgumentsAt($timing, $function, $args, $message = '%s') { 228 $mock = & MockFunction::_instance($function); 229 $mock->expectArgumentsAt($timing, $function, $args, $message); 230 } 231 232 /** 233 * Sets an expectation for the number of times 234 * a function will be called. 235 * @param string $function Function call to test. 236 * @param integer $count Number of times it should 237 * have been called at tally. 238 * @param string $message Overridden message. 239 * @access public 240 * @static 241 */ 242 function expectCallCount($function, $count, $message = '%s') { 243 $mock = & MockFunction::_instance($function); 244 $mock->expectCallCount($function, $count, $message); 245 } 246 247 /** 248 * Sets the number of times a function may be called 249 * before a test failure is triggered. 250 * @param string $function Function call to test. 251 * @param integer $count Most number of times it should 252 * have been called. 253 * @param string $message Overridden message. 254 * @access public 255 * @static 256 */ 257 function expectMaximumCallCount($function, $count, $message = '%s') { 258 $mock = & MockFunction::_instance($function); 259 $mock->expectMaximumCallCount($function, $count, $message); 260 } 261 262 /** 263 * Sets the minimum number of times the function must be called 264 * otherwise a test failure is triggered 265 * @param string $function Function call to test. 266 * @param integer $count Least number of times it should 267 * have been called. 268 * @param string $message Overridden message. 269 * @access public 270 * @static 271 */ 272 function expectMinimumCallCount($function, $count, $message = '%s') { 273 $mock = & MockFunction::_instance($function); 274 $mock->expectMinimumCallCount($function, $count, $message); 275 } 276 277 /** 278 * Convenience method for barring a function 279 * call. 280 * @param string $function Function call to ban. 281 * @param string $message Overridden message. 282 * @access public 283 * @static 284 */ 285 function expectNever($function, $message = '%s') { 286 $mock = & MockFunction::_instance($function); 287 $mock->expectNever($function, $message); 288 } 289 290 /** 291 * Convenience method for a single function 292 * call. 293 * @param string $function Function call to track. 294 * @param array $args Expected argument list or 295 * false for any arguments. 296 * @param string $message Overridden message. 297 * @access public 298 * @static 299 */ 300 function expectOnce($function, $args = false, $message = '%s') { 301 $mock = & MockFunction::_instance($function); 302 $mock->expectOnce($function, $args, $message); 303 } 304 305 /** 306 * Convenience method for requiring a function 307 * call. 308 * @param string $function Function call to track. 309 * @param array $args Expected argument list or 310 * false for any arguments. 311 * @param string $message Overridden message. 312 * @access public 313 * @static 314 */ 315 function expectAtLeastOnce($function, $args = false, $message = '%s') { 316 $mock = & MockFunction::_instance($function); 317 $mock->expectAtLeastOnce($function, $args, $message); 318 } 319 320 function atTestEnd($function) { 321 $mock = & MockFunction::_instance($function); 322 $mock->atTestEnd($function); 323 } 324 325 } 326 327 /** 328 * Represents a single, mocked function, tracking calls made to it 329 * @package SimpleTest 330 * @subpackage MockFunctions 331 */ 332 class SimpleMockFunction extends SimpleMock { 333 334 var $_is_mocked = FALSE; 335 var $_generator; 336 337 /** 338 * Sets up the mock, creating a generator depending on whether 339 * the function is already declared 340 * @param string $function Name of function being mocked 341 */ 342 function SimpleMockFunction($function) { 343 344 SimpleMock :: SimpleMock(); 345 346 if ( function_exists($function) ) { 347 $this->_generator = new SimpleDeclaredFunctionGenerator($function); 348 } else { 349 $this->_generator = new SimpleUndeclaredFunctionGenerator($function); 350 } 351 352 } 353 354 /** 355 * Deploys the mock function implementation into PHP's function 356 * table, replacing any existing implementation 357 * @access public 358 */ 359 function deploy() { 360 361 if ( !$this->_is_mocked ) { 362 363 $this->_is_mocked = TRUE; 364 $this->_generator->deploy(); 365 366 } 367 368 } 369 370 /** 371 * Restores the state of PHP's function table to that before 372 * the mock function was deployed. Removes the mock function 373 * implementation and restores any existing implementation of 374 * that function 375 * @access public 376 */ 377 function restore() { 378 379 if ( $this->_is_mocked ) { 380 381 $this->_is_mocked = FALSE; 382 $this->_generator->restore(); 383 384 } 385 386 } 387 388 } 389 390 /** 391 * Base class for deploying and restoring from mock functions 392 * @package SimpleTest 393 * @subpackage MockFunctions 394 * @abstract 395 */ 396 class SimpleFunctionGenerator { 397 398 var $_function; 399 400 /** 401 * @TODO Validate the function name (as it's being used in eval) 402 * @TODO Add list of illegal functions (ones which must not be mocked 403 * as they will break SimpleTest, which uses them) 404 * @param string $function Name of function being mocked 405 */ 406 function SimpleFunctionGenerator($function) { 407 $this->_function = $function; 408 } 409 410 /** 411 * Generates the mock function implementation, using eval 412 * @access private 413 */ 414 function _generateMockFunction() { 415 $code = "function " . $this->_function . "() {\n"; 416 $code .= " \$args = func_get_args();\n"; 417 $code .= " \$mock = & MockFunction::_instance('".$this->_function."');\n"; 418 $code .= " \$result = &\$mock->_invoke(\"".$this->_function."\", \$args);\n"; 419 $code .= " return \$result;\n"; 420 $code .= "}\n"; 421 eval($code); 422 } 423 } 424 425 /** 426 * Mock function generator for functions which have already been declared 427 * @package SimpleTest 428 * @subpackage MockFunctions 429 */ 430 class SimpleDeclaredFunctionGenerator extends SimpleFunctionGenerator { 431 432 var $_tmp_function = NULL; 433 434 /** 435 * Invokes the _generateTmpFnFname 436 * @param string $function Name of function being mocked 437 */ 438 function SimpleDeclaredFunctionGenerator($function) { 439 440 SimpleFunctionGenerator::SimpleFunctionGenerator($function); 441 $this->_generateTmpFnFname(); 442 443 } 444 445 /** 446 * Generates a temporary name for the declared function implementation 447 * which is will be renamed to while the mock function is in use 448 * @access private 449 */ 450 function _generateTmpFnFname() { 451 static $count = 1; 452 $this->_tmp_function = 'tmp_'.md5(time().$this->_function.$count); 453 $count++; 454 } 455 456 /** 457 * Deploys the mock function implementation 458 * @access public 459 */ 460 function deploy() { 461 462 runkit_function_rename( 463 $this->_function, 464 $this->_tmp_function 465 ) or 466 trigger_error('Error archiving real function implementation', 467 E_USER_ERROR); 468 469 $this->_generateMockFunction(); 470 } 471 472 /** 473 * Removes the mock function implementation and restores 474 * the previously declared implementation 475 * @access public 476 */ 477 function restore() { 478 479 runkit_function_remove($this->_function) or 480 trigger_error('Error removing mock function', 481 E_USER_ERROR); 482 483 runkit_function_rename( 484 $this->_tmp_function, 485 $this->_function 486 ) or 487 trigger_error('Error restoring real function', 488 E_USER_ERROR); 489 } 490 } 491 492 /** 493 * Mock function generator for functions which have not 494 * already been declared 495 * @package SimpleTest 496 * @subpackage MockFunctions 497 */ 498 class SimpleUndeclaredFunctionGenerator extends SimpleFunctionGenerator { 499 500 /** 501 * Deploys the mock function implementation 502 * @access public 503 */ 504 function deploy() { 505 $this->_generateMockFunction(); 506 } 507 508 /** 509 * Removes the mock function implementation 510 * @access public 511 */ 512 function restore() { 513 runkit_function_remove($this->_function) or 514 trigger_error('Error removing mock function', 515 E_USER_ERROR); 516 } 517 518 } 519
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Fri Nov 21 01:30:02 2008 | Cross-referenced by PHPXref 0.7 |