[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/lib/simpletestlib/ -> mock_objects.php (source)

   1  <?php
   2      /**
   3       *    base include file for SimpleTest
   4       *    @package    SimpleTest
   5       *    @subpackage    MockObjects
   6       *    @version    $Id$
   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       */
 165      class CallCountExpectation extends SimpleExpectation {
 166          var $_method;
 167          var $_count;
 168  
 169          /**
 170           *    Stashes the method and expected count for later
 171           *    reporting.
 172           *    @param string $method    Name of method to confirm against.
 173           *    @param integer $count    Expected number of calls.
 174           *    @param string $message   Custom error message.
 175           */
 176          function CallCountExpectation($method, $count, $message = '%s') {
 177              $this->_method = $method;
 178              $this->_count = $count;
 179              $this->SimpleExpectation($message);
 180          }
 181  
 182          /**
 183           *    Tests the assertion. True if correct.
 184           *    @param integer $compare     Measured call count.
 185           *    @return boolean             True if expected.
 186           *    @access public
 187           */
 188          function test($compare) {
 189              return ($this->_count == $compare);
 190          }
 191  
 192          /**
 193           *    Reports the comparison.
 194           *    @param integer $compare     Measured call count.
 195           *    @return string              Message to show.
 196           *    @access public
 197           */
 198          function testMessage($compare) {
 199              return 'Expected call count for [' . $this->_method .
 200                      '] was [' . $this->_count .
 201                      '] got [' . $compare . ']';
 202          }
 203      }
 204  
 205      /**
 206       *    Confirms that the number of calls on a method is as expected.
 207       */
 208      class MinimumCallCountExpectation extends SimpleExpectation {
 209          var $_method;
 210          var $_count;
 211  
 212          /**
 213           *    Stashes the method and expected count for later
 214           *    reporting.
 215           *    @param string $method    Name of method to confirm against.
 216           *    @param integer $count    Minimum number of calls.
 217           *    @param string $message   Custom error message.
 218           */
 219          function MinimumCallCountExpectation($method, $count, $message = '%s') {
 220              $this->_method = $method;
 221              $this->_count = $count;
 222              $this->SimpleExpectation($message);
 223          }
 224  
 225          /**
 226           *    Tests the assertion. True if correct.
 227           *    @param integer $compare     Measured call count.
 228           *    @return boolean             True if enough.
 229           *    @access public
 230           */
 231          function test($compare) {
 232              return ($this->_count <= $compare);
 233          }
 234  
 235          /**
 236           *    Reports the comparison.
 237           *    @param integer $compare     Measured call count.
 238           *    @return string              Message to show.
 239           *    @access public
 240           */
 241          function testMessage($compare) {
 242              return 'Minimum call count for [' . $this->_method .
 243                      '] was [' . $this->_count .
 244                      '] got [' . $compare . ']';
 245          }
 246      }
 247  
 248      /**
 249       *    Confirms that the number of calls on a method is as expected.
 250       */
 251      class MaximumCallCountExpectation extends SimpleExpectation {
 252          var $_method;
 253          var $_count;
 254  
 255          /**
 256           *    Stashes the method and expected count for later
 257           *    reporting.
 258           *    @param string $method    Name of method to confirm against.
 259           *    @param integer $count    Minimum number of calls.
 260           *    @param string $message   Custom error message.
 261           */
 262          function MaximumCallCountExpectation($method, $count, $message = '%s') {
 263              $this->_method = $method;
 264              $this->_count = $count;
 265              $this->SimpleExpectation($message);
 266          }
 267  
 268          /**
 269           *    Tests the assertion. True if correct.
 270           *    @param integer $compare     Measured call count.
 271           *    @return boolean             True if not over.
 272           *    @access public
 273           */
 274          function test($compare) {
 275              return ($this->_count >= $compare);
 276          }
 277  
 278          /**
 279           *    Reports the comparison.
 280           *    @param integer $compare     Measured call count.
 281           *    @return string              Message to show.
 282           *    @access public
 283           */
 284          function testMessage($compare) {
 285              return 'Maximum call count for [' . $this->_method .
 286                      '] was [' . $this->_count .
 287                      '] got [' . $compare . ']';
 288          }
 289      }
 290  
 291      /**
 292       *    Retrieves values and references by searching the
 293       *    parameter lists until a match is found.
 294       *    @package SimpleTest
 295       *    @subpackage MockObjects
 296       */
 297      class CallMap {
 298          var $_map;
 299  
 300          /**
 301           *    Creates an empty call map.
 302           *    @access public
 303           */
 304          function CallMap() {
 305              $this->_map = array();
 306          }
 307  
 308          /**
 309           *    Stashes a value against a method call.
 310           *    @param array $parameters    Arguments including wildcards.
 311           *    @param mixed $value         Value copied into the map.
 312           *    @access public
 313           */
 314          function addValue($parameters, $value) {
 315              $this->addReference($parameters, $value);
 316          }
 317  
 318          /**
 319           *    Stashes a reference against a method call.
 320           *    @param array $parameters    Array of arguments (including wildcards).
 321           *    @param mixed $reference     Array reference placed in the map.
 322           *    @access public
 323           */
 324          function addReference($parameters, &$reference) {
 325              $place = count($this->_map);
 326              $this->_map[$place] = array();
 327              $this->_map[$place]["params"] = new ParametersExpectation($parameters);
 328              $this->_map[$place]["content"] = &$reference;
 329          }
 330  
 331          /**
 332           *    Searches the call list for a matching parameter
 333           *    set. Returned by reference.
 334           *    @param array $parameters    Parameters to search by
 335           *                                without wildcards.
 336           *    @return object              Object held in the first matching
 337           *                                slot, otherwise null.
 338           *    @access public
 339           */
 340          function &findFirstMatch($parameters) {
 341              $slot = $this->_findFirstSlot($parameters);
 342              if (!isset($slot)) {
 343                  $null = null;
 344                  return $null;
 345              }
 346              return $slot["content"];
 347          }
 348  
 349          /**
 350           *    Searches the call list for a matching parameter
 351           *    set. True if successful.
 352           *    @param array $parameters    Parameters to search by
 353           *                                without wildcards.
 354           *    @return boolean             True if a match is present.
 355           *    @access public
 356           */
 357          function isMatch($parameters) {
 358              return ($this->_findFirstSlot($parameters) != null);
 359          }
 360  
 361          /**
 362           *    Searches the map for a matching item.
 363           *    @param array $parameters    Parameters to search by
 364           *                                without wildcards.
 365           *    @return array               Reference to slot or null.
 366           *    @access private
 367           */
 368          function &_findFirstSlot($parameters) {
 369              $count = count($this->_map);
 370              for ($i = 0; $i < $count; $i++) {
 371                  if ($this->_map[$i]["params"]->test($parameters)) {
 372                      return $this->_map[$i];
 373                  }
 374              }
 375              $null = null;
 376              return $null;
 377          }
 378      }
 379  
 380      /**
 381       *    An empty collection of methods that can have their
 382       *    return values set and expectations made of the
 383       *    calls upon them. The mock will assert the
 384       *    expectations against it's attached test case in
 385       *    addition to the server stub behaviour.
 386       *    @package SimpleTest
 387       *    @subpackage MockObjects
 388       */
 389      class SimpleMock {
 390          var $_wildcard = MOCK_ANYTHING;
 391          var $_is_strict = true;
 392          var $_returns;
 393          var $_return_sequence;
 394          var $_call_counts;
 395          var $_expected_counts;
 396          var $_max_counts;
 397          var $_expected_args;
 398          var $_expected_args_at;
 399  
 400          /**
 401           *    Creates an empty return list and expectation list.
 402           *    All call counts are set to zero.
 403           *    @param SimpleTestCase $test    Test case to test expectations in.
 404           *    @param mixed $wildcard         Parameter matching wildcard.
 405           *    @param boolean $is_strict      Enables method name checks on
 406           *                                   expectations.
 407           */
 408          function SimpleMock() {
 409              $this->_returns = array();
 410              $this->_return_sequence = array();
 411              $this->_call_counts = array();
 412              $test = &$this->_getCurrentTestCase();
 413              $test->tell($this);
 414              $this->_expected_counts = array();
 415              $this->_max_counts = array();
 416              $this->_expected_args = array();
 417              $this->_expected_args_at = array();
 418          }
 419  
 420          /**
 421           *    Disables a name check when setting expectations.
 422           *    This hack is needed for the partial mocks.
 423           *    @access public
 424           */
 425          function disableExpectationNameChecks() {
 426              $this->_is_strict = false;
 427          }
 428  
 429          /**
 430           *    Changes the default wildcard object.
 431           *    @param mixed $wildcard         Parameter matching wildcard.
 432           *    @access public
 433           */
 434          function setWildcard($wildcard) {
 435              $this->_wildcard = $wildcard;
 436          }
 437  
 438          /**
 439           *    Finds currently running test.
 440           *    @return SimpeTestCase    Current test case.
 441           *    @access protected
 442           */
 443          function &_getCurrentTestCase() {
 444              $context = &SimpleTest::getContext();
 445              return $context->getTest();
 446          }
 447  
 448          /**
 449           *    Die if bad arguments array is passed
 450           *    @param mixed $args     The arguments value to be checked.
 451           *    @param string $task    Description of task attempt.
 452           *    @return boolean        Valid arguments
 453           *    @access private
 454           */
 455          function _checkArgumentsIsArray($args, $task) {
 456              if (! is_array($args)) {
 457                  trigger_error(
 458                      "Cannot $task as \$args parameter is not an array",
 459                      E_USER_ERROR);
 460              }
 461          }
 462  
 463          /**
 464           *    Triggers a PHP error if the method is not part
 465           *    of this object.
 466           *    @param string $method        Name of method.
 467           *    @param string $task          Description of task attempt.
 468           *    @access protected
 469           */
 470          function _dieOnNoMethod($method, $task) {
 471              if ($this->_is_strict && ! method_exists($this, $method)) {
 472                  trigger_error(
 473                          "Cannot $task as no $method}() in class " . get_class($this),
 474                          E_USER_ERROR);
 475              }
 476          }
 477  
 478          /**
 479           *    Replaces wildcard matches with wildcard
 480           *    expectations in the argument list.
 481           *    @param array $args      Raw argument list.
 482           *    @return array           Argument list with
 483           *                            expectations.
 484           *    @access private
 485           */
 486          function _replaceWildcards($args) {
 487              if ($args === false) {
 488                  return false;
 489              }
 490              for ($i = 0; $i < count($args); $i++) {
 491                  if ($args[$i] === $this->_wildcard) {
 492                      $args[$i] = new AnythingExpectation();
 493                  }
 494              }
 495              return $args;
 496          }
 497  
 498          /**
 499           *    Adds one to the call count of a method.
 500           *    @param string $method        Method called.
 501           *    @param array $args           Arguments as an array.
 502           *    @access protected
 503           */
 504          function _addCall($method, $args) {
 505              if (!isset($this->_call_counts[$method])) {
 506                  $this->_call_counts[$method] = 0;
 507              }
 508              $this->_call_counts[$method]++;
 509          }
 510  
 511          /**
 512           *    Fetches the call count of a method so far.
 513           *    @param string $method        Method name called.
 514           *    @return                      Number of calls so far.
 515           *    @access public
 516           */
 517          function getCallCount($method) {
 518              $this->_dieOnNoMethod($method, "get call count");
 519              $method = strtolower($method);
 520              if (! isset($this->_call_counts[$method])) {
 521                  return 0;
 522              }
 523              return $this->_call_counts[$method];
 524          }
 525  
 526          /**
 527           *    Sets a return for a parameter list that will
 528           *    be passed by value for all calls to this method.
 529           *    @param string $method       Method name.
 530           *    @param mixed $value         Result of call passed by value.
 531           *    @param array $args          List of parameters to match
 532           *                                including wildcards.
 533           *    @access public
 534           */
 535          function setReturnValue($method, $value, $args = false) {
 536              $this->_dieOnNoMethod($method, "set return value");
 537              $args = $this->_replaceWildcards($args);
 538              $method = strtolower($method);
 539              if (! isset($this->_returns[$method])) {
 540                  $this->_returns[$method] = new CallMap();
 541              }
 542              $this->_returns[$method]->addValue($args, $value);
 543          }
 544  
 545          /**
 546           *    Sets a return for a parameter list that will
 547           *    be passed by value only when the required call count
 548           *    is reached.
 549           *    @param integer $timing   Number of calls in the future
 550           *                             to which the result applies. If
 551           *                             not set then all calls will return
 552           *                             the value.
 553           *    @param string $method    Method name.
 554           *    @param mixed $value      Result of call passed by value.
 555           *    @param array $args       List of parameters to match
 556           *                             including wildcards.
 557           *    @access public
 558           */
 559          function setReturnValueAt($timing, $method, $value, $args = false) {
 560              $this->_dieOnNoMethod($method, "set return value sequence");
 561              $args = $this->_replaceWildcards($args);
 562              $method = strtolower($method);
 563              if (! isset($this->_return_sequence[$method])) {
 564                  $this->_return_sequence[$method] = array();
 565              }
 566              if (! isset($this->_return_sequence[$method][$timing])) {
 567                  $this->_return_sequence[$method][$timing] = new CallMap();
 568              }
 569              $this->_return_sequence[$method][$timing]->addValue($args, $value);
 570          }
 571  
 572          /**
 573           *    Sets a return for a parameter list that will
 574           *    be passed by reference for all calls.
 575           *    @param string $method       Method name.
 576           *    @param mixed $reference     Result of the call will be this object.
 577           *    @param array $args          List of parameters to match
 578           *                                including wildcards.
 579           *    @access public
 580           */
 581          function setReturnReference($method, &$reference, $args = false) {
 582              $this->_dieOnNoMethod($method, "set return reference");
 583              $args = $this->_replaceWildcards($args);
 584              $method = strtolower($method);
 585              if (! isset($this->_returns[$method])) {
 586                  $this->_returns[$method] = new CallMap();
 587              }
 588              $this->_returns[$method]->addReference($args, $reference);
 589          }
 590  
 591          /**
 592           *    Sets a return for a parameter list that will
 593           *    be passed by value only when the required call count
 594           *    is reached.
 595           *    @param integer $timing    Number of calls in the future
 596           *                              to which the result applies. If
 597           *                              not set then all calls will return
 598           *                              the value.
 599           *    @param string $method     Method name.
 600           *    @param mixed $reference   Result of the call will be this object.
 601           *    @param array $args        List of parameters to match
 602           *                              including wildcards.
 603           *    @access public
 604           */
 605          function setReturnReferenceAt($timing, $method, &$reference, $args = false) {
 606              $this->_dieOnNoMethod($method, "set return reference sequence");
 607              $args = $this->_replaceWildcards($args);
 608              $method = strtolower($method);
 609              if (! isset($this->_return_sequence[$method])) {
 610                  $this->_return_sequence[$method] = array();
 611              }
 612              if (! isset($this->_return_sequence[$method][$timing])) {
 613                  $this->_return_sequence[$method][$timing] = new CallMap();
 614              }
 615              $this->_return_sequence[$method][$timing]->addReference($args, $reference);
 616          }
 617  
 618          /**
 619           *    Sets up an expected call with a set of
 620           *    expected parameters in that call. All
 621           *    calls will be compared to these expectations
 622           *    regardless of when the call is made.
 623           *    @param string $method        Method call to test.
 624           *    @param array $args           Expected parameters for the call
 625           *                                 including wildcards.
 626           *    @param string $message       Overridden message.
 627           *    @access public
 628           */
 629          function expect($method, $args, $message = '%s') {
 630              $this->_dieOnNoMethod($method, 'set expected arguments');
 631              $this->_checkArgumentsIsArray($args, 'set expected arguments');
 632              $args = $this->_replaceWildcards($args);
 633              $message .= Mock::getExpectationLine();
 634              $this->_expected_args[strtolower($method)] =
 635                      new ParametersExpectation($args, $message);
 636          }
 637  
 638          /**
 639           *    @deprecated
 640           */
 641          function expectArguments($method, $args, $message = '%s') {
 642              return $this->expect($method, $args, $message);
 643          }
 644  
 645          /**
 646           *    Sets up an expected call with a set of
 647           *    expected parameters in that call. The
 648           *    expected call count will be adjusted if it
 649           *    is set too low to reach this call.
 650           *    @param integer $timing    Number of calls in the future at
 651           *                              which to test. Next call is 0.
 652           *    @param string $method     Method call to test.
 653           *    @param array $args        Expected parameters for the call
 654           *                              including wildcards.
 655           *    @param string $message    Overridden message.
 656           *    @access public
 657           */
 658          function expectAt($timing, $method, $args, $message = '%s') {
 659              $this->_dieOnNoMethod($method, 'set expected arguments at time');
 660              $this->_checkArgumentsIsArray($args, 'set expected arguments at time');
 661              $args = $this->_replaceWildcards($args);
 662              if (! isset($this->_expected_args_at[$timing])) {
 663                  $this->_expected_args_at[$timing] = array();
 664              }
 665              $method = strtolower($method);
 666              $message .= Mock::getExpectationLine();
 667              $this->_expected_args_at[$timing][$method] =
 668                      new ParametersExpectation($args, $message);
 669          }
 670  
 671          /**
 672           *    @deprecated
 673           */
 674          function expectArgumentsAt($timing, $method, $args, $message = '%s') {
 675              return $this->expectAt($timing, $method, $args, $message);
 676          }
 677  
 678          /**
 679           *    Sets an expectation for the number of times
 680           *    a method will be called. The tally method
 681           *    is used to check this.
 682           *    @param string $method        Method call to test.
 683           *    @param integer $count        Number of times it should
 684           *                                 have been called at tally.
 685           *    @param string $message       Overridden message.
 686           *    @access public
 687           */
 688          function expectCallCount($method, $count, $message = '%s') {
 689              $this->_dieOnNoMethod($method, 'set expected call count');
 690              $message .= Mock::getExpectationLine();
 691              $this->_expected_counts[strtolower($method)] =
 692                      new CallCountExpectation($method, $count, $message);
 693          }
 694  
 695          /**
 696           *    Sets the number of times a method may be called
 697           *    before a test failure is triggered.
 698           *    @param string $method        Method call to test.
 699           *    @param integer $count        Most number of times it should
 700           *                                 have been called.
 701           *    @param string $message       Overridden message.
 702           *    @access public
 703           */
 704          function expectMaximumCallCount($method, $count, $message = '%s') {
 705              $this->_dieOnNoMethod($method, 'set maximum call count');
 706              $message .= Mock::getExpectationLine();
 707              $this->_max_counts[strtolower($method)] =
 708                      new MaximumCallCountExpectation($method, $count, $message);
 709          }
 710  
 711          /**
 712           *    Sets the number of times to call a method to prevent
 713           *    a failure on the tally.
 714           *    @param string $method      Method call to test.
 715           *    @param integer $count      Least number of times it should
 716           *                               have been called.
 717           *    @param string $message     Overridden message.
 718           *    @access public
 719           */
 720          function expectMinimumCallCount($method, $count, $message = '%s') {
 721              $this->_dieOnNoMethod($method, 'set minimum call count');
 722              $message .= Mock::getExpectationLine();
 723              $this->_expected_counts[strtolower($method)] =
 724                      new MinimumCallCountExpectation($method, $count, $message);
 725          }
 726  
 727          /**
 728           *    Convenience method for barring a method
 729           *    call.
 730           *    @param string $method        Method call to ban.
 731           *    @param string $message       Overridden message.
 732           *    @access public
 733           */
 734          function expectNever($method, $message = '%s') {
 735              $this->expectMaximumCallCount($method, 0, $message);
 736          }
 737  
 738          /**
 739           *    Convenience method for a single method
 740           *    call.
 741           *    @param string $method     Method call to track.
 742           *    @param array $args        Expected argument list or
 743           *                              false for any arguments.
 744           *    @param string $message    Overridden message.
 745           *    @access public
 746           */
 747          function expectOnce($method, $args = false, $message = '%s') {
 748              $this->expectCallCount($method, 1, $message);
 749              if ($args !== false) {
 750                  $this->expectArguments($method, $args, $message);
 751              }
 752          }
 753  
 754          /**
 755           *    Convenience method for requiring a method
 756           *    call.
 757           *    @param string $method       Method call to track.
 758           *    @param array $args          Expected argument list or
 759           *                                false for any arguments.
 760           *    @param string $message      Overridden message.
 761           *    @access public
 762           */
 763          function expectAtLeastOnce($method, $args = false, $message = '%s') {
 764              $this->expectMinimumCallCount($method, 1, $message);
 765              if ($args !== false) {
 766                  $this->expectArguments($method, $args, $message);
 767              }
 768          }
 769  
 770          /**
 771           *    @deprecated
 772           */
 773          function tally() {
 774          }
 775  
 776          /**
 777           *    Receives event from unit test that the current
 778           *    test method has finished. Totals up the call
 779           *    counts and triggers a test assertion if a test
 780           *    is present for expected call counts.
 781           *    @param string $test_method    Current method name.
 782           *    @param SimpleTestCase $test   Test to send message to.
 783           *    @access public
 784           */
 785          function atTestEnd($test_method, &$test) {
 786              foreach ($this->_expected_counts as $method => $expectation) {
 787                  $test->assert($expectation, $this->getCallCount($method));
 788              }
 789              foreach ($this->_max_counts as $method => $expectation) {
 790                  if ($expectation->test($this->getCallCount($method))) {
 791                      $test->assert($expectation, $this->getCallCount($method));
 792                  }
 793              }
 794          }
 795  
 796          /**
 797           *    Returns the expected value for the method name
 798           *    and checks expectations. Will generate any
 799           *    test assertions as a result of expectations
 800           *    if there is a test present.
 801           *    @param string $method       Name of method to simulate.
 802           *    @param array $args          Arguments as an array.
 803           *    @return mixed               Stored return.
 804           *    @access private
 805           */
 806          function &_invoke($method, $args) {
 807              $method = strtolower($method);
 808              $step = $this->getCallCount($method);
 809              $this->_addCall($method, $args);
 810              $this->_checkExpectations($method, $args, $step);
 811              $result = &$this->_getReturn($method, $args, $step);
 812              return $result;
 813          }
 814          /**
 815           *    Finds the return value matching the incoming
 816           *    arguments. If there is no matching value found
 817           *    then an error is triggered.
 818           *    @param string $method      Method name.
 819           *    @param array $args         Calling arguments.
 820           *    @param integer $step       Current position in the
 821           *                               call history.
 822           *    @return mixed              Stored return.
 823           *    @access protected
 824           */
 825          function &_getReturn($method, $args, $step) {
 826              if (isset($this->_return_sequence[$method][$step])) {
 827                  if ($this->_return_sequence[$method][$step]->isMatch($args)) {
 828                      $result = &$this->_return_sequence[$method][$step]->findFirstMatch($args);
 829                      return $result;
 830                  }
 831              }
 832              if (isset($this->_returns[$method])) {
 833                  $result = &$this->_returns[$method]->findFirstMatch($args);
 834                  return $result;
 835              }
 836              $null = null;
 837              return $null;
 838          }
 839  
 840          /**
 841           *    Tests the arguments against expectations.
 842           *    @param string $method        Method to check.
 843           *    @param array $args           Argument list to match.
 844           *    @param integer $timing       The position of this call
 845           *                                 in the call history.
 846           *    @access private
 847           */
 848          function _checkExpectations($method, $args, $timing) {
 849              $test = &$this->_getCurrentTestCase();
 850              if (isset($this->_max_counts[$method])) {
 851                  if (! $this->_max_counts[$method]->test($timing + 1)) {
 852                      $test->assert($this->_max_counts[$method], $timing + 1);
 853                  }
 854              }
 855              if (isset($this->_expected_args_at[$timing][$method])) {
 856                  $test->assert(
 857                          $this->_expected_args_at[$timing][$method],
 858                          $args,
 859                          "Mock method [$method] at [$timing] -> %s");
 860              } elseif (isset($this->_expected_args[$method])) {
 861                  $test->assert(
 862                          $this->_expected_args[$method],
 863                          $args,
 864                          "Mock method [$method] -> %s");
 865              }
 866          }
 867      }
 868  
 869      /**
 870       *    Static methods only service class for code generation of
 871       *    mock objects.
 872       *    @package SimpleTest
 873       *    @subpackage MockObjects
 874       */
 875      class Mock {
 876  
 877          /**
 878           *    Factory for mock object classes.
 879           *    @access public
 880           */
 881          function Mock() {
 882              trigger_error('Mock factory methods are static.');
 883          }
 884  
 885          /**
 886           *    Clones a class' interface and creates a mock version
 887           *    that can have return values and expectations set.
 888           *    @param string $class         Class to clone.
 889           *    @param string $mock_class    New class name. Default is
 890           *                                 the old name with "Mock"
 891           *                                 prepended.
 892           *    @param array $methods        Additional methods to add beyond
 893           *                                 those in th cloned class. Use this
 894           *                                 to emulate the dynamic addition of
 895           *                                 methods in the cloned class or when
 896           *                                 the class hasn't been written yet.
 897           *    @static
 898           *    @access public
 899           */
 900          function generate($class, $mock_class = false, $methods = false) {
 901              $generator = new MockGenerator($class, $mock_class);
 902              return $generator->generate($methods);
 903          }
 904  
 905          /**
 906           *    Generates a version of a class with selected
 907           *    methods mocked only. Inherits the old class
 908           *    and chains the mock methods of an aggregated
 909           *    mock object.
 910           *    @param string $class            Class to clone.
 911           *    @param string $mock_class       New class name.
 912           *    @param array $methods           Methods to be overridden
 913           *                                    with mock versions.
 914           *    @static
 915           *    @access public
 916           */
 917          function generatePartial($class, $mock_class, $methods) {
 918              $generator = new MockGenerator($class, $mock_class);
 919              return $generator->generatePartial($methods);
 920          }
 921  
 922          /**
 923           *    Uses a stack trace to find the line of an assertion.
 924           *    @access public
 925           *    @static
 926           */
 927          function getExpectationLine() {
 928              $trace = new SimpleStackTrace(array('expect'));
 929              return $trace->traceMethod();
 930          }
 931      }
 932  
 933      /**
 934       *    @deprecated
 935       */
 936      class Stub extends Mock {
 937      }
 938  
 939      /**
 940       *    Service class for code generation of mock objects.
 941       *    @package SimpleTest
 942       *    @subpackage MockObjects
 943       */
 944      class MockGenerator {
 945          var $_class;
 946          var $_mock_class;
 947          var $_mock_base;
 948          var $_reflection;
 949  
 950          function MockGenerator($class, $mock_class) {
 951              $this->_class = $class;
 952              $this->_mock_class = $mock_class;
 953              $this->_mock_base = SimpleTest::getMockBaseClass();
 954              $this->_reflection = new SimpleReflection($this->_class);
 955          }
 956  
 957          /**
 958           *    Clones a class' interface and creates a mock version
 959           *    that can have return values and expectations set.
 960           *    @param array $methods        Additional methods to add beyond
 961           *                                 those in th cloned class. Use this
 962           *                                 to emulate the dynamic addition of
 963           *                                 methods in the cloned class or when
 964           *                                 the class hasn't been written yet.
 965           *    @access public
 966           */
 967          function generate($methods) {
 968              if (! $this->_reflection->classOrInterfaceExists()) {
 969                  return false;
 970              }
 971              if (! $this->_mock_class) {
 972                  $this->_mock_class = 'Mock' . $this->_class;
 973              }
 974              $mock_reflection = new SimpleReflection($this->_mock_class);
 975              if ($mock_reflection->classExistsSansAutoload()) {
 976                  return false;
 977              }
 978              return eval(
 979                      $this->_createClassCode($methods ? $methods : array()) .
 980                      " return true;");
 981          }
 982  
 983          /**
 984           *    Generates a version of a class with selected
 985           *    methods mocked only. Inherits the old class
 986           *    and chains the mock methods of an aggregated
 987           *    mock object.
 988           *    @param array $methods           Methods to be overridden
 989           *                                    with mock versions.
 990           *    @access public
 991           */
 992          function generatePartial($methods) {
 993              if (! $this->_reflection->classExists($this->_class)) {
 994                  return false;
 995              }
 996              $mock_reflection = new SimpleReflection($this->_mock_class);
 997              if ($mock_reflection->classExistsSansAutoload()) {
 998                  trigger_error('Partial mock class [' . $this->_mock_class . '] already exists');
 999                  return false;
1000              }
1001              return eval($this->_extendClassCode($methods));
1002          }
1003  
1004          /**
1005           *    The new mock class code as a string.
1006           *    @param array $methods          Additional methods.
1007           *    @return string                 Code for new mock class.
1008           *    @access private
1009           */
1010          function _createClassCode($methods) {
1011              $implements = '';
1012              $interfaces = $this->_reflection->getInterfaces();
1013              if (function_exists('spl_classes')) {
1014                  $interfaces = array_diff($interfaces, array('Traversable'));
1015              }
1016              if (count($interfaces) > 0) {
1017                  $implements = 'implements ' . implode(', ', $interfaces);
1018              }
1019              $code = "class " . $this->_mock_class . " extends " . $this->_mock_base . " $implements {\n";
1020              $code .= "    function " . $this->_mock_class . "() {\n";
1021              $code .= "        \$this->" . $this->_mock_base . "();\n";
1022              $code .= "    }\n";
1023              $code .= $this->_createHandlerCode($methods);
1024              $code .= "}\n";
1025              return $code;
1026          }
1027  
1028          /**
1029           *    The extension class code as a string. The class
1030           *    composites a mock object and chains mocked methods
1031           *    to it.
1032           *    @param array  $methods       Mocked methods.
1033           *    @return string               Code for a new class.
1034           *    @access private
1035           */
1036          function _extendClassCode($methods) {
1037              $code  = "class " . $this->_mock_class . " extends " . $this->_class . " {\n";
1038              $code .= "    var \$_mock;\n";
1039              $code .= $this->_addMethodList($methods);
1040              $code .= "\n";
1041              $code .= "    function " . $this->_mock_class . "() {\n";
1042              $code .= "        \$this->_mock = &new " . $this->_mock_base . "();\n";
1043              $code .= "        \$this->_mock->disableExpectationNameChecks();\n";
1044              $code .= "    }\n";
1045              $code .= $this->_chainMockReturns();
1046              $code .= $this->_chainMockExpectations();
1047              $code .= $this->_overrideMethods($methods);
1048              $code .= "}\n";
1049              return $code;
1050          }
1051  
1052          /**
1053           *    Creates code within a class to generate replaced
1054           *    methods. All methods call the _invoke() handler
1055           *    with the method name and the arguments in an
1056           *    array.
1057           *    @param array $methods    Additional methods.
1058           *    @access private
1059           */
1060          function _createHandlerCode($methods) {
1061              $code = '';
1062              $methods = array_merge($methods, $this->_reflection->getMethods());
1063              foreach ($methods as $method) {
1064                  if ($this->_isConstructor($method)) {
1065                      continue;
1066                  }
1067                  $mock_reflection = new SimpleReflection($this->_mock_base);
1068                  if (in_array($method, $mock_reflection->getMethods())) {
1069                      continue;
1070                  }
1071                  $code .= "    " . $this->_reflection->getSignature($method) . " {\n";
1072                  $code .= "        \$args = func_get_args();\n";
1073                  $code .= "        \$result = &\$this->_invoke(\"$method\", \$args);\n";
1074                  $code .= "        return \$result;\n";
1075                  $code .= "    }\n";
1076              }
1077              return $code;
1078          }
1079  
1080          /**
1081           *    Tests to see if a special PHP method is about to
1082           *    be stubbed by mistake.
1083           *    @param string $method    Method name.
1084           *    @return boolean          True if special.
1085           *    @access private
1086           */
1087          function _isConstructor($method) {
1088              return in_array(
1089                      strtolower($method),
1090                      array('__construct', '__destruct', '__clone'));
1091          }
1092  
1093          /**
1094           *    Creates a list of mocked methods for error checking.
1095           *    @param array $methods       Mocked methods.
1096           *    @return string              Code for a method list.
1097           *    @access private
1098           */
1099          function _addMethodList($methods) {
1100              return "    var \$_mocked_methods = array('" . implode("', '", $methods) . "');\n";
1101          }
1102  
1103          /**
1104           *    Creates code to abandon the expectation if not mocked.
1105           *    @param string $alias       Parameter name of method name.
1106           *    @return string             Code for bail out.
1107           *    @access private
1108           */
1109          function _bailOutIfNotMocked($alias) {
1110              $code  = "        if (! in_array($alias, \$this->_mocked_methods)) {\n";
1111              $code .= "            trigger_error(\"Method [$alias] is not mocked\");\n";
1112              $code .= "            \$null = null;\n";
1113              $code .= "            return \$null;\n";
1114              $code .= "        }\n";
1115              return $code;
1116          }
1117  
1118          /**
1119           *    Creates source code for chaining to the composited
1120           *    mock object.
1121           *    @return string           Code for mock set up.
1122           *    @access private
1123           */
1124          function _chainMockReturns() {
1125              $code  = "    function setReturnValue(\$method, \$value, \$args = false) {\n";
1126              $code .= $this->_bailOutIfNotMocked("\$method");
1127              $code .= "        \$this->_mock->setReturnValue(\$method, \$value, \$args);\n";
1128              $code .= "    }\n";
1129              $code .= "    function setReturnValueAt(\$timing, \$method, \$value, \$args = false) {\n";
1130              $code .= $this->_bailOutIfNotMocked("\$method");
1131              $code .= "        \$this->_mock->setReturnValueAt(\$timing, \$method, \$value, \$args);\n";
1132              $code .= "    }\n";
1133              $code .= "    function setReturnReference(\$method, &\$ref, \$args = false) {\n";
1134              $code .= $this->_bailOutIfNotMocked("\$method");
1135              $code .= "        \$this->_mock->setReturnReference(\$method, \$ref, \$args);\n";
1136              $code .= "    }\n";
1137              $code .= "    function setReturnReferenceAt(\$timing, \$method, &\$ref, \$args = false) {\n";
1138              $code .= $this->_bailOutIfNotMocked("\$method");
1139              $code .= "        \$this->_mock->setReturnReferenceAt(\$timing, \$method, \$ref, \$args);\n";
1140              $code .= "    }\n";
1141              return $code;
1142          }
1143  
1144          /**
1145           *    Creates source code for chaining to an aggregated
1146           *    mock object.
1147           *    @return string                 Code for expectations.
1148           *    @access private
1149           */
1150          function _chainMockExpectations() {
1151              $code  = "    function expect(\$method, \$args = false) {\n";
1152              $code .= $this->_bailOutIfNotMocked("\$method");
1153              $code .= "        \$this->_mock->expect(\$method, \$args);\n";
1154              $code .= "    }\n";
1155              $code .= "    function expectArguments(\$method, \$args = false) {\n";
1156              $code .= $this->_bailOutIfNotMocked("\$method");
1157              $code .= "        \$this->_mock->expectArguments(\$method, \$args);\n";
1158              $code .= "    }\n";
1159              $code .= "    function expectAt(\$timing, \$method, \$args = false) {\n";
1160              $code .= $this->_bailOutIfNotMocked("\$method");
1161              $code .= "        \$this->_mock->expectArgumentsAt(\$timing, \$method, \$args);\n";
1162              $code .= "    }\n";
1163              $code .= "    function expectArgumentsAt(\$timing, \$method, \$args = false) {\n";
1164              $code .= $this->_bailOutIfNotMocked("\$method");
1165              $code .= "        \$this->_mock->expectArgumentsAt(\$timing, \$method, \$args);\n";
1166              $code .= "    }\n";
1167              $code .= "    function expectCallCount(\$method, \$count) {\n";
1168              $code .= $this->_bailOutIfNotMocked("\$method");
1169              $code .= "        \$this->_mock->expectCallCount(\$method, \$count);\n";
1170              $code .= "    }\n";
1171              $code .= "    function expectMaximumCallCount(\$method, \$count) {\n";
1172              $code .= $this->_bailOutIfNotMocked("\$method");
1173              $code .= "        \$this->_mock->expectMaximumCallCount(\$method, \$count);\n";
1174              $code .= "    }\n";
1175              $code .= "    function expectMinimumCallCount(\$method, \$count) {\n";
1176              $code .= $this->_bailOutIfNotMocked("\$method");
1177              $code .= "        \$this->_mock->expectMinimumCallCount(\$method, \$count);\n";
1178              $code .= "    }\n";
1179              $code .= "    function expectNever(\$method) {\n";
1180              $code .= $this->_bailOutIfNotMocked("\$method");
1181              $code .= "        \$this->_mock->expectNever(\$method);\n";
1182              $code .= "    }\n";
1183              $code .= "    function expectOnce(\$method, \$args = false) {\n";
1184              $code .= $this->_bailOutIfNotMocked("\$method");
1185              $code .= "        \$this->_mock->expectOnce(\$method, \$args);\n";
1186              $code .= "    }\n";
1187              $code .= "    function expectAtLeastOnce(\$method, \$args = false) {\n";
1188              $code .= $this->_bailOutIfNotMocked("\$method");
1189              $code .= "        \$this->_mock->expectAtLeastOnce(\$method, \$args);\n";
1190              $code .= "    }\n";
1191              $code .= "    function tally() {\n";
1192              $code .= "        \$this->_mock->tally();\n";
1193              $code .= "    }\n";
1194              return $code;
1195          }
1196  
1197          /**
1198           *    Creates source code to override a list of methods
1199           *    with mock versions.
1200           *    @param array $methods    Methods to be overridden
1201           *                             with mock versions.
1202           *    @return string           Code for overridden chains.
1203           *    @access private
1204           */
1205          function _overrideMethods($methods) {
1206              $code = "";
1207              foreach ($methods as $method) {
1208                  $code .= "    " . $this->_reflection->getSignature($method) . " {\n";
1209                  $code .= "        \$args = func_get_args();\n";
1210                  $code .= "        \$result = &\$this->_mock->_invoke(\"$method\", \$args);\n";
1211                  $code .= "        return \$result;\n";
1212                  $code .= "    }\n";
1213              }
1214              return $code;
1215          }
1216      }
1217  ?>


Generated: Wed Jan 14 11:33:29 2009 Cross-referenced by PHPXref 0.7