[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/_test/lib/ -> mock_functions.php (source)

   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  


Generated: Fri Nov 21 01:30:02 2008 Cross-referenced by PHPXref 0.7