Source for file mock_objects.php

Documentation is available at mock_objects.php

  1. <?php
  2. /**
  3.  *  base include file for SimpleTest
  4.  *  @package    SimpleTest
  5.  *  @subpackage MockObjects
  6.  *  @version    $Id: mock_objects.php 1953 2009-09-20 01:26:25Z jsweat $
  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. require_once(dirname(__FILE__'/reflection_php5.php');
  16. /**#@-*/
  17.  
  18. /**
  19.  * Default character simpletest will substitute for any value
  20.  */
  21. if (defined('MOCK_ANYTHING')) {
  22.     define('MOCK_ANYTHING''*');
  23. }
  24.  
  25. /**
  26.  *    Parameter comparison assertion.
  27.  *    @package SimpleTest
  28.  *    @subpackage MockObjects
  29.  */
  30.     private $expected;
  31.  
  32.     /**
  33.      *    Sets the expected parameter list.
  34.      *    @param array $parameters  Array of parameters including
  35.      *                               those that are wildcarded.
  36.      *                               If the value is not an array
  37.      *                               then it is considered to match any.
  38.      *    @param string $message    Customised message on failure.
  39.      *    @access public
  40.      */
  41.     function __construct($expected false$message '%s'{
  42.         parent::__construct($message);
  43.         $this->expected $expected;
  44.     }
  45.  
  46.     /**
  47.      *    Tests the assertion. True if correct.
  48.      *    @param array $parameters     Comparison values.
  49.      *    @return boolean              True if correct.
  50.      *    @access public
  51.      */
  52.     function test($parameters{
  53.         if (is_array($this->expected)) {
  54.             return true;
  55.         }
  56.         if (count($this->expected!= count($parameters)) {
  57.             return false;
  58.         }
  59.         for ($i 0$i count($this->expected)$i++{
  60.             if ($this->testParameter($parameters[$i]$this->expected[$i])) {
  61.                 return false;
  62.             }
  63.         }
  64.         return true;
  65.     }
  66.  
  67.     /**
  68.      *    Tests an individual parameter.
  69.      *    @param mixed $parameter    Value to test.
  70.      *    @param mixed $expected     Comparison value.
  71.      *    @return boolean            True if expectation
  72.      *                                fulfilled.
  73.      *    @access private
  74.      */
  75.     protected function testParameter($parameter$expected{
  76.         $comparison $this->coerceToExpectation($expected);
  77.         return $comparison->test($parameter);
  78.     }
  79.  
  80.     /**
  81.      *    Returns a human readable test message.
  82.      *    @param array $comparison   Incoming parameter list.
  83.      *    @return string             Description of success
  84.      *                                or failure.
  85.      *    @access public
  86.      */
  87.     function testMessage($parameters{
  88.         if ($this->test($parameters)) {
  89.             return "Expectation of " count($this->expected.
  90.                     " arguments of [" $this->renderArguments($this->expected.
  91.                     "] is correct";
  92.         else {
  93.             return $this->describeDifference($this->expected$parameters);
  94.         }
  95.     }
  96.  
  97.     /**
  98.      *    Message to display if expectation differs from
  99.      *    the parameters actually received.
  100.      *    @param array $expected      Expected parameters as list.
  101.      *    @param array $parameters    Actual parameters received.
  102.      *    @return string              Description of difference.
  103.      *    @access private
  104.      */
  105.     protected function describeDifference($expected$parameters{
  106.         if (count($expected!= count($parameters)) {
  107.             return "Expected " count($expected.
  108.                     " arguments of [" $this->renderArguments($expected.
  109.                     "] but got " count($parameters.
  110.                     " arguments of [" $this->renderArguments($parameters"]";
  111.         }
  112.         $messages array();
  113.         for ($i 0$i count($expected)$i++{
  114.             $comparison $this->coerceToExpectation($expected[$i]);
  115.             if ($comparison->test($parameters[$i])) {
  116.                 $messages["parameter " ($i 1" with [" .
  117.                         $comparison->overlayMessage($parameters[$i]$this->getDumper()) "]";
  118.             }
  119.         }
  120.         return "Parameter expectation differs at " implode(" and "$messages);
  121.     }
  122.  
  123.     /**
  124.      *    Creates an identical expectation if the
  125.      *    object/value is not already some type
  126.      *    of expectation.
  127.      *    @param mixed $expected      Expected value.
  128.      *    @return SimpleExpectation   Expectation object.
  129.      *    @access private
  130.      */
  131.     protected function coerceToExpectation($expected{
  132.         if (SimpleExpectation::isExpectation($expected)) {
  133.             return $expected;
  134.         }
  135.         return new IdenticalExpectation($expected);
  136.     }
  137.  
  138.     /**
  139.      *    Renders the argument list as a string for
  140.      *    messages.
  141.      *    @param array $args    Incoming arguments.
  142.      *    @return string        Simple description of type and value.
  143.      *    @access private
  144.      */
  145.     protected function renderArguments($args{
  146.         $descriptions array();
  147.         if (is_array($args)) {
  148.             foreach ($args as $arg{
  149.                 $dumper new SimpleDumper();
  150.                 $descriptions[$dumper->describeValue($arg);
  151.             }
  152.         }
  153.         return implode(', '$descriptions);
  154.     }
  155. }
  156.  
  157. /**
  158.  *    Confirms that the number of calls on a method is as expected.
  159.  *  @package    SimpleTest
  160.  *  @subpackage MockObjects
  161.  */
  162.     private $method;
  163.     private $count;
  164.  
  165.     /**
  166.      *    Stashes the method and expected count for later
  167.      *    reporting.
  168.      *    @param string $method    Name of method to confirm against.
  169.      *    @param integer $count    Expected number of calls.
  170.      *    @param string $message   Custom error message.
  171.      */
  172.     function __construct($method$count$message '%s'{
  173.         $this->method $method;
  174.         $this->count $count;
  175.         parent::__construct($message);
  176.     }
  177.  
  178.     /**
  179.      *    Tests the assertion. True if correct.
  180.      *    @param integer $compare     Measured call count.
  181.      *    @return boolean             True if expected.
  182.      *    @access public
  183.      */
  184.     function test($compare{
  185.         return ($this->count == $compare);
  186.     }
  187.  
  188.     /**
  189.      *    Reports the comparison.
  190.      *    @param integer $compare     Measured call count.
  191.      *    @return string              Message to show.
  192.      *    @access public
  193.      */
  194.     function testMessage($compare{
  195.         return 'Expected call count for [' $this->method .
  196.                 '] was [' $this->count .
  197.                 '] got [' $compare ']';
  198.     }
  199. }
  200.  
  201. /**
  202.  *    Confirms that the number of calls on a method is as expected.
  203.  *  @package    SimpleTest
  204.  *  @subpackage MockObjects
  205.  */
  206.     private $method;
  207.     private $count;
  208.  
  209.     /**
  210.      *    Stashes the method and expected count for later
  211.      *    reporting.
  212.      *    @param string $method    Name of method to confirm against.
  213.      *    @param integer $count    Minimum number of calls.
  214.      *    @param string $message   Custom error message.
  215.      */
  216.     function __construct($method$count$message '%s'{
  217.         $this->method $method;
  218.         $this->count $count;
  219.         parent::__construct($message);
  220.     }
  221.  
  222.     /**
  223.      *    Tests the assertion. True if correct.
  224.      *    @param integer $compare     Measured call count.
  225.      *    @return boolean             True if enough.
  226.      *    @access public
  227.      */
  228.     function test($compare{
  229.         return ($this->count <= $compare);
  230.     }
  231.  
  232.     /**
  233.      *    Reports the comparison.
  234.      *    @param integer $compare     Measured call count.
  235.      *    @return string              Message to show.
  236.      *    @access public
  237.      */
  238.     function testMessage($compare{
  239.         return 'Minimum call count for [' $this->method .
  240.                 '] was [' $this->count .
  241.                 '] got [' $compare ']';
  242.     }
  243. }
  244.  
  245. /**
  246.  *    Confirms that the number of calls on a method is as expected.
  247.  *    @package      SimpleTest
  248.  *    @subpackage   MockObjects
  249.  */
  250.     private $method;
  251.     private $count;
  252.  
  253.     /**
  254.      *    Stashes the method and expected count for later
  255.      *    reporting.
  256.      *    @param string $method    Name of method to confirm against.
  257.      *    @param integer $count    Minimum number of calls.
  258.      *    @param string $message   Custom error message.
  259.      */
  260.     function __construct($method$count$message '%s'{
  261.         $this->method $method;
  262.         $this->count $count;
  263.         parent::__construct($message);
  264.     }
  265.  
  266.     /**
  267.      *    Tests the assertion. True if correct.
  268.      *    @param integer $compare     Measured call count.
  269.      *    @return boolean             True if not over.
  270.      *    @access public
  271.      */
  272.     function test($compare{
  273.         return ($this->count >= $compare);
  274.     }
  275.  
  276.     /**
  277.      *    Reports the comparison.
  278.      *    @param integer $compare     Measured call count.
  279.      *    @return string              Message to show.
  280.      *    @access public
  281.      */
  282.     function testMessage($compare{
  283.         return 'Maximum call count for [' $this->method .
  284.                 '] was [' $this->count .
  285.                 '] got [' $compare ']';
  286.     }
  287. }
  288.  
  289. /**
  290.  *    Retrieves method actions by searching the
  291.  *    parameter lists until an expected match is found.
  292.  *    @package SimpleTest
  293.  *    @subpackage MockObjects
  294.  */
  295.     private $map;
  296.  
  297.     /**
  298.      *    Creates an empty call map.
  299.      *    @access public
  300.      */
  301.     function __construct({
  302.         $this->map array();
  303.     }
  304.  
  305.     /**
  306.      *    Stashes a reference against a method call.
  307.      *    @param array $parameters    Array of arguments (including wildcards).
  308.      *    @param mixed $action        Reference placed in the map.
  309.      *    @access public
  310.      */
  311.     function add($parameters$action{
  312.         $place count($this->map);
  313.         $this->map[$placearray();
  314.         $this->map[$place]['params'new ParametersExpectation($parameters);
  315.         $this->map[$place]['content'$action;
  316.     }
  317.  
  318.     /**
  319.      *    Searches the call list for a matching parameter
  320.      *    set. Returned by reference.
  321.      *    @param array $parameters    Parameters to search by
  322.      *                                 without wildcards.
  323.      *    @return object              Object held in the first matching
  324.      *                                 slot, otherwise null.
  325.      *    @access public
  326.      */
  327.     function &findFirstAction($parameters{
  328.         $slot $this->findFirstSlot($parameters);
  329.         if (isset($slot&& isset($slot['content'])) {
  330.             return $slot['content'];
  331.         }
  332.         $null null;
  333.         return $null;
  334.     }
  335.  
  336.     /**
  337.      *    Searches the call list for a matching parameter
  338.      *    set. True if successful.
  339.      *    @param array $parameters    Parameters to search by
  340.      *                                 without wildcards.
  341.      *    @return boolean             True if a match is present.
  342.      *    @access public
  343.      */
  344.     function isMatch($parameters{
  345.         return ($this->findFirstSlot($parameters!= null);
  346.     }
  347.     
  348.     /**
  349.      *    Compares the incoming parameters with the
  350.      *    internal expectation. Uses the incoming $test
  351.      *    to dispatch the test message.
  352.      *    @param SimpleTestCase $test   Test to dispatch to.
  353.      *    @param array $parameters      The actual calling arguments.
  354.      *    @param string $message        The message to overlay.
  355.      *    @access public
  356.      */
  357.     function test($test$parameters$message{
  358.     }
  359.  
  360.     /**
  361.      *    Searches the map for a matching item.
  362.      *    @param array $parameters    Parameters to search by
  363.      *                                 without wildcards.
  364.      *    @return array               Reference to slot or null.
  365.      *    @access private
  366.      */
  367.     function &findFirstSlot($parameters{
  368.         $count count($this->map);
  369.         for ($i 0$i $count$i++{
  370.             if ($this->map[$i]["params"]->test($parameters)) {
  371.                 return $this->map[$i];
  372.             }
  373.         }
  374.         $null null;
  375.         return $null;
  376.     }
  377. }
  378.  
  379. /**
  380.  *    Allows setting of actions against call signatures either
  381.  *    at a specific time, or always. Specific time settings
  382.  *    trump lasting ones, otherwise the most recently added
  383.  *    will mask an earlier match.
  384.  *    @package SimpleTest
  385.  *    @subpackage MockObjects
  386.  */
  387.     private $wildcard MOCK_ANYTHING;
  388.     private $always;
  389.     private $at;
  390.     
  391.     /**
  392.      *    Sets up an empty response schedule.
  393.      *    Creates an empty call map.
  394.      */
  395.     function __construct({
  396.         $this->always array();
  397.         $this->at array();
  398.     }
  399.     
  400.     /**
  401.      *    Stores an action against a signature that
  402.      *    will always fire unless masked by a time
  403.      *    specific one.
  404.      *    @param string $method        Method name.
  405.      *    @param array $args           Calling parameters.
  406.      *    @param SimpleAction $action  Actually simpleByValue, etc.
  407.      *    @access public
  408.      */
  409.     function register($method$args$action{
  410.         $args $this->replaceWildcards($args);
  411.         $method strtolower($method);
  412.         if (isset($this->always[$method])) {
  413.             $this->always[$methodnew SimpleSignatureMap();
  414.         }
  415.         $this->always[$method]->add($args$action);
  416.     }
  417.     
  418.     /**
  419.      *    Stores an action against a signature that
  420.      *    will fire at a specific time in the future.
  421.      *    @param integer $step         delay of calls to this method,
  422.      *                                  0 is next.
  423.      *    @param string $method        Method name.
  424.      *    @param array $args           Calling parameters.
  425.      *    @param SimpleAction $action  Actually SimpleByValue, etc.
  426.      *    @access public
  427.      */
  428.     function registerAt($step$method$args$action{
  429.         $args $this->replaceWildcards($args);
  430.         $method strtolower($method);
  431.         if (isset($this->at[$method])) {
  432.             $this->at[$methodarray();
  433.         }
  434.         if (isset($this->at[$method][$step])) {
  435.             $this->at[$method][$stepnew SimpleSignatureMap();
  436.         }
  437.         $this->at[$method][$step]->add($args$action);
  438.     }
  439.     
  440.     /**
  441.      *  Sets up an expectation on the argument list.
  442.      *  @param string $method       Method to test.
  443.      *  @param array $args          Bare arguments or list of
  444.      *                               expectation objects.
  445.      *  @param string $message      Failure message.
  446.      */
  447.     function expectArguments($method$args$message{
  448.         $args $this->replaceWildcards($args);
  449.         $message .= Mock::getExpectationLine();
  450.         $this->expected_args[strtolower($method)=
  451.                 new ParametersExpectation($args$message);
  452.  
  453.     }
  454.     
  455.     /**
  456.      *    Actually carry out the action stored previously,
  457.      *    if the parameters match.
  458.      *    @param integer $step      Time of call.
  459.      *    @param string $method     Method name.
  460.      *    @param array $args        The parameters making up the
  461.      *                               rest of the call.
  462.      *    @return mixed             The result of the action.
  463.      */
  464.     function &respond($step$method$args{
  465.         $method strtolower($method);
  466.         if (isset($this->at[$method][$step])) {
  467.             if ($this->at[$method][$step]->isMatch($args)) {
  468.                 $action $this->at[$method][$step]->findFirstAction($args);
  469.                 if (isset($action)) {
  470.                     return $action->act();
  471.                 }
  472.             }
  473.         }
  474.         if (isset($this->always[$method])) {
  475.             $action $this->always[$method]->findFirstAction($args);
  476.             if (isset($action)) {
  477.                 return $action->act();
  478.             }
  479.         }
  480.         $null null;
  481.         return $null;
  482.     }
  483.     
  484.     /**
  485.      *    Replaces wildcard matches with wildcard
  486.      *    expectations in the argument list.
  487.      *    @param array $args      Raw argument list.
  488.      *    @return array           Argument list with
  489.      *                             expectations.
  490.      *    @access private
  491.      */
  492.     protected function replaceWildcards($args{
  493.         if ($args === false{
  494.             return false;
  495.         }
  496.         for ($i 0$i count($args)$i++{
  497.             if ($args[$i=== $this->wildcard{
  498.                 $args[$inew AnythingExpectation();
  499.             }
  500.         }
  501.         return $args;
  502.     }
  503. }
  504.  
  505. /**
  506.  *    A type of SimpleMethodAction.
  507.  *    Stashes a value for returning later. Follows usual
  508.  *    PHP5 semantics of objects being returned by reference.
  509.  *    @package SimpleTest
  510.  *    @subpackage MockObjects
  511.  */
  512. class SimpleReturn {
  513.     private $value;
  514.     
  515.     /**
  516.      *    Stashes it for later.
  517.      *    @param mixed $value     You need to clone objects
  518.      *                             if you want copy semantics
  519.      *                             for these.
  520.      *    @access public
  521.      */
  522.     function __construct($value{
  523.         $this->value $value;
  524.     }
  525.     
  526.     /**
  527.      *    Returns the value stored earlier.
  528.      *    @return mixed    Whatever was stashed.
  529.      *    @access public
  530.      */
  531.     function act({
  532.         return $this->value;
  533.     }
  534. }
  535.  
  536. /**
  537.  *    A type of SimpleMethodAction.
  538.  *    Stashes a reference for returning later.
  539.  *    @package SimpleTest
  540.  *    @subpackage MockObjects
  541.  */
  542.     private $reference;
  543.     
  544.     /**
  545.      *    Stashes it for later.
  546.      *    @param mixed $reference     Actual PHP4 style reference.
  547.      *    @access public
  548.      */
  549.     function __construct(&$reference{
  550.         $this->reference &$reference;
  551.     }
  552.     
  553.     /**
  554.      *    Returns the reference stored earlier.
  555.      *    @return mixed    Whatever was stashed.
  556.      *    @access public
  557.      */
  558.     function &act({
  559.         return $this->reference;
  560.     }
  561. }
  562.  
  563. /**
  564.  *    A type of SimpleMethodAction.
  565.  *    Stashes a value for returning later.
  566.  *    @package SimpleTest
  567.  *    @subpackage MockObjects
  568.  */
  569. class SimpleByValue {
  570.     private $value;
  571.     
  572.     /**
  573.      *    Stashes it for later.
  574.      *    @param mixed $value     You need to clone objects
  575.      *                             if you want copy semantics
  576.      *                             for these.
  577.      *    @access public
  578.      */
  579.     function __construct($value{
  580.         $this->value $value;
  581.     }
  582.     
  583.     /**
  584.      *    Returns the value stored earlier.
  585.      *    @return mixed    Whatever was stashed.
  586.      *    @access public
  587.      */
  588.     function &act({
  589.         $dummy $this->value;
  590.         return $dummy;
  591.     }
  592. }
  593.  
  594. /**
  595.  *    A type of SimpleMethodAction.
  596.  *    Stashes an exception for throwing later.
  597.  *    @package SimpleTest
  598.  *    @subpackage MockObjects
  599.  */
  600. class SimpleThrower {
  601.     private $exception;
  602.     
  603.     /**
  604.      *    Stashes it for later.
  605.      *    @param Exception $exception    The exception object to throw.
  606.      *    @access public
  607.      */
  608.     function __construct($exception{
  609.         $this->exception $exception;
  610.     }
  611.     
  612.     /**
  613.      *    Throws the exceptins stashed earlier.
  614.      *    @access public
  615.      */
  616.     function act({
  617.         throw $this->exception;
  618.     }
  619. }
  620.  
  621. /**
  622.  *    A type of SimpleMethodAction.
  623.  *    Stashes an error for emitting later.
  624.  *    @package SimpleTest
  625.  *    @subpackage MockObjects
  626.  */
  627.     private $error;
  628.     private $severity;
  629.     
  630.     /**
  631.      *    Stashes an error to throw later.
  632.      *    @param string $error      Error message.
  633.      *    @param integer $severity  PHP error constant, e.g E_USER_ERROR.
  634.      *    @access public
  635.      */
  636.     function __construct($error$severity{
  637.         $this->error $error;
  638.         $this->severity $severity;
  639.     }
  640.     
  641.     /**
  642.      *    Triggers the stashed error.
  643.      *    @access public
  644.      */
  645.     function &act({
  646.         trigger_error($this->error$this->severity);
  647.         $null null;
  648.         return $null;
  649.     }
  650. }
  651.  
  652. /**
  653.  *    A base class or delegate that extends an
  654.  *    empty collection of methods that can have their
  655.  *    return values set and expectations made of the
  656.  *    calls upon them. The mock will assert the
  657.  *    expectations against it's attached test case in
  658.  *    addition to the server stub behaviour or returning
  659.  *    preprogrammed responses.
  660.  *    @package SimpleTest
  661.  *    @subpackage MockObjects
  662.  */
  663. class SimpleMock {
  664.     private $actions;
  665.     private $expectations;
  666.     private $wildcard MOCK_ANYTHING;
  667.     private $is_strict true;
  668.     private $call_counts;
  669.     private $expected_counts;
  670.     private $max_counts;
  671.     private $expected_args;
  672.     private $expected_args_at;
  673.  
  674.     /**
  675.      *    Creates an empty action list and expectation list.
  676.      *    All call counts are set to zero.
  677.      *    @access public
  678.      */
  679.     function SimpleMock({
  680.         $this->actions new SimpleCallSchedule();
  681.         $this->expectations new SimpleCallSchedule();
  682.         $this->call_counts array();
  683.         $this->expected_counts array();
  684.         $this->max_counts array();
  685.         $this->expected_args array();
  686.         $this->expected_args_at array();
  687.         $this->getCurrentTestCase()->tell($this);
  688.     }
  689.     
  690.     /**
  691.      *    Disables a name check when setting expectations.
  692.      *    This hack is needed for the partial mocks.
  693.      *    @access public
  694.      */
  695.     function disableExpectationNameChecks({
  696.         $this->is_strict false;
  697.     }
  698.  
  699.     /**
  700.      *    Finds currently running test.
  701.      *    @return SimpeTestCase    Current test case.
  702.      *    @access protected
  703.      */
  704.     protected function getCurrentTestCase({
  705.         return SimpleTest::getContext()->getTest();
  706.     }
  707.  
  708.     /**
  709.      *    Die if bad arguments array is passed.
  710.      *    @param mixed $args     The arguments value to be checked.
  711.      *    @param string $task    Description of task attempt.
  712.      *    @return boolean        Valid arguments
  713.      *    @access private
  714.      */
  715.     protected function checkArgumentsIsArray($args$task{
  716.         if (is_array($args)) {
  717.             trigger_error(
  718.                 "Cannot $task as \$args parameter is not an array",
  719.                 E_USER_ERROR);
  720.         }
  721.     }
  722.  
  723.     /**
  724.      *    Triggers a PHP error if the method is not part
  725.      *    of this object.
  726.      *    @param string $method        Name of method.
  727.      *    @param string $task          Description of task attempt.
  728.      *    @access protected
  729.      */
  730.     protected function dieOnNoMethod($method$task{
  731.         if ($this->is_strict && method_exists($this$method)) {
  732.             trigger_error(
  733.                     "Cannot $task as no ${method}() in class get_class($this),
  734.                     E_USER_ERROR);
  735.         }
  736.     }
  737.  
  738.     /**
  739.      *    Replaces wildcard matches with wildcard
  740.      *    expectations in the argument list.
  741.      *    @param array $args      Raw argument list.
  742.      *    @return array           Argument list with
  743.      *                             expectations.
  744.      *    @access private
  745.      */
  746.     function replaceWildcards($args{
  747.         if ($args === false{
  748.             return false;
  749.         }
  750.         for ($i 0$i count($args)$i++{
  751.             if ($args[$i=== $this->wildcard{
  752.                 $args[$inew AnythingExpectation();
  753.             }
  754.         }
  755.         return $args;
  756.     }
  757.  
  758.     /**
  759.      *    Adds one to the call count of a method.
  760.      *    @param string $method        Method called.
  761.      *    @param array $args           Arguments as an array.
  762.      *    @access protected
  763.      */
  764.     protected function addCall($method$args{
  765.         if (isset($this->call_counts[$method])) {
  766.             $this->call_counts[$method0;
  767.         }
  768.         $this->call_counts[$method]++;
  769.     }
  770.  
  771.     /**
  772.      *    Fetches the call count of a method so far.
  773.      *    @param string $method        Method name called.
  774.      *    @return integer              Number of calls so far.
  775.      *    @access public
  776.      */
  777.     function getCallCount($method{
  778.         $this->dieOnNoMethod($method"get call count");
  779.         $method strtolower($method);
  780.         if (isset($this->call_counts[$method])) {
  781.             return 0;
  782.         }
  783.         return $this->call_counts[$method];
  784.     }
  785.  
  786.     /**
  787.      *    Sets a return for a parameter list that will
  788.      *    be passed on by all calls to this method that match.
  789.      *    @param string $method       Method name.
  790.      *    @param mixed $value         Result of call by value/handle.
  791.      *    @param array $args          List of parameters to match
  792.      *                                 including wildcards.
  793.      *    @access public
  794.      */
  795.     function returns($method$value$args false{
  796.         $this->dieOnNoMethod($method"set return");
  797.         $this->actions->register($method$argsnew SimpleReturn($value));
  798.     }
  799.  
  800.     /**
  801.      *    Sets a return for a parameter list that will
  802.      *    be passed only when the required call count
  803.      *    is reached.
  804.      *    @param integer $timing   Number of calls in the future
  805.      *                              to which the result applies. If
  806.      *                              not set then all calls will return
  807.      *                              the value.
  808.      *    @param string $method    Method name.
  809.      *    @param mixed $value      Result of call passed.
  810.      *    @param array $args       List of parameters to match
  811.      *                              including wildcards.
  812.      *    @access public
  813.      */
  814.     function returnsAt($timing$method$value$args false{
  815.         $this->dieOnNoMethod($method"set return value sequence");
  816.         $this->actions->registerAt($timing$method$argsnew SimpleReturn($value));
  817.     }
  818.  
  819.     /**
  820.      *    Sets a return for a parameter list that will
  821.      *    be passed by value for all calls to this method.
  822.      *    @param string $method       Method name.
  823.      *    @param mixed $value         Result of call passed by value.
  824.      *    @param array $args          List of parameters to match
  825.      *                                 including wildcards.
  826.      *    @access public
  827.      */
  828.     function returnsByValue($method$value$args false{
  829.         $this->dieOnNoMethod($method"set return value");
  830.         $this->actions->register($method$argsnew SimpleByValue($value));
  831.     }
  832.     
  833.     /** @deprecated */
  834.     function setReturnValue($method$value$args false{
  835.         $this->returnsByValue($method$value$args);
  836.     }
  837.  
  838.     /**
  839.      *    Sets a return for a parameter list that will
  840.      *    be passed by value only when the required call count
  841.      *    is reached.
  842.      *    @param integer $timing   Number of calls in the future
  843.      *                              to which the result applies. If
  844.      *                              not set then all calls will return
  845.      *                              the value.
  846.      *    @param string $method    Method name.
  847.      *    @param mixed $value      Result of call passed by value.
  848.      *    @param array $args       List of parameters to match
  849.      *                              including wildcards.
  850.      *    @access public
  851.      */
  852.     function returnsByValueAt($timing$method$value$args false{
  853.         $this->dieOnNoMethod($method"set return value sequence");
  854.         $this->actions->registerAt($timing$method$argsnew SimpleByValue($value));
  855.     }
  856.     
  857.     /** @deprecated */
  858.     function setReturnValueAt($timing$method$value$args false{
  859.         $this->returnsByValueAt($timing$method$value$args);
  860.     }
  861.  
  862.     /**
  863.      *    Sets a return for a parameter list that will
  864.      *    be passed by reference for all calls.
  865.      *    @param string $method       Method name.
  866.      *    @param mixed $reference     Result of the call will be this object.
  867.      *    @param array $args          List of parameters to match
  868.      *                                 including wildcards.
  869.      *    @access public
  870.      */
  871.     function returnsByReference($method&$reference$args false{
  872.         $this->dieOnNoMethod($method"set return reference");
  873.         $this->actions->register($method$argsnew SimpleByReference($reference));
  874.     }
  875.     
  876.     /** @deprecated */
  877.     function setReturnReference($method&$reference$args false{
  878.         $this->returnsByReference($method$reference$args);
  879.     }
  880.     
  881.     /**
  882.      *    Sets a return for a parameter list that will
  883.      *    be passed by value only when the required call count
  884.      *    is reached.
  885.      *    @param integer $timing    Number of calls in the future
  886.      *                               to which the result applies. If
  887.      *                               not set then all calls will return
  888.      *                               the value.
  889.      *    @param string $method     Method name.
  890.      *    @param mixed $reference   Result of the call will be this object.
  891.      *    @param array $args        List of parameters to match
  892.      *                               including wildcards.
  893.      *    @access public
  894.      */
  895.     function returnsByReferenceAt($timing$method&$reference$args false{
  896.         $this->dieOnNoMethod($method"set return reference sequence");
  897.         $this->actions->registerAt($timing$method$argsnew SimpleByReference($reference));
  898.     }
  899.     
  900.     /** @deprecated */
  901.     function setReturnReferenceAt($timing$method&$reference$args false{
  902.         $this->returnsByReferenceAt($timing$method$reference$args);
  903.     }
  904.     
  905.     /**
  906.      *    Sets up an expected call with a set of
  907.      *    expected parameters in that call. All
  908.      *    calls will be compared to these expectations
  909.      *    regardless of when the call is made.
  910.      *    @param string $method        Method call to test.
  911.      *    @param array $args           Expected parameters for the call
  912.      *                                  including wildcards.
  913.      *    @param string $message       Overridden message.
  914.      *    @access public
  915.      */
  916.     function expect($method$args$message '%s'{
  917.         $this->dieOnNoMethod($method'set expected arguments');
  918.         $this->checkArgumentsIsArray($args'set expected arguments');
  919.         $this->expectations->expectArguments($method$args$message);
  920.         $args $this->replaceWildcards($args);
  921.         $message .= Mock::getExpectationLine();
  922.         $this->expected_args[strtolower($method)=
  923.                 new ParametersExpectation($args$message);
  924.     }
  925.  
  926.     /**
  927.      *    Sets up an expected call with a set of
  928.      *    expected parameters in that call. The
  929.      *    expected call count will be adjusted if it
  930.      *    is set too low to reach this call.
  931.      *    @param integer $timing    Number of calls in the future at
  932.      *                               which to test. Next call is 0.
  933.      *    @param string $method     Method call to test.
  934.      *    @param array $args        Expected parameters for the call
  935.      *                               including wildcards.
  936.      *    @param string $message    Overridden message.
  937.      *    @access public
  938.      */
  939.     function expectAt($timing$method$args$message '%s'{
  940.         $this->dieOnNoMethod($method'set expected arguments at time');
  941.         $this->checkArgumentsIsArray($args'set expected arguments at time');
  942.         $args $this->replaceWildcards($args);
  943.         if (isset($this->expected_args_at[$timing])) {
  944.             $this->expected_args_at[$timingarray();
  945.         }
  946.         $method strtolower($method);
  947.         $message .= Mock::getExpectationLine();
  948.         $this->expected_args_at[$timing][$method=
  949.                 new ParametersExpectation($args$message);
  950.     }
  951.  
  952.     /**
  953.      *    Sets an expectation for the number of times
  954.      *    a method will be called. The tally method
  955.      *    is used to check this.
  956.      *    @param string $method        Method call to test.
  957.      *    @param integer $count        Number of times it should
  958.      *                                  have been called at tally.
  959.      *    @param string $message       Overridden message.
  960.      *    @access public
  961.      */
  962.     function expectCallCount($method$count$message '%s'{
  963.         $this->dieOnNoMethod($method'set expected call count');
  964.         $message .= Mock::getExpectationLine();
  965.         $this->expected_counts[strtolower($method)=
  966.                 new CallCountExpectation($method$count$message);
  967.     }
  968.  
  969.     /**
  970.      *    Sets the number of times a method may be called
  971.      *    before a test failure is triggered.
  972.      *    @param string $method        Method call to test.
  973.      *    @param integer $count        Most number of times it should
  974.      *                                  have been called.
  975.      *    @param string $message       Overridden message.
  976.      *    @access public
  977.      */
  978.     function expectMaximumCallCount($method$count$message '%s'{
  979.         $this->dieOnNoMethod($method'set maximum call count');
  980.         $message .= Mock::getExpectationLine();
  981.         $this->max_counts[strtolower($method)=
  982.                 new MaximumCallCountExpectation($method$count$message);
  983.     }
  984.  
  985.     /**
  986.      *    Sets the number of times to call a method to prevent
  987.      *    a failure on the tally.
  988.      *    @param string $method      Method call to test.
  989.      *    @param integer $count      Least number of times it should
  990.      *                                have been called.
  991.      *    @param string $message     Overridden message.
  992.      *    @access public
  993.      */
  994.     function expectMinimumCallCount($method$count$message '%s'{
  995.         $this->dieOnNoMethod($method'set minimum call count');
  996.         $message .= Mock::getExpectationLine();
  997.         $this->expected_counts[strtolower($method)=
  998.                 new MinimumCallCountExpectation($method$count$message);
  999.     }
  1000.  
  1001.     /**
  1002.      *    Convenience method for barring a method
  1003.      *    call.
  1004.      *    @param string $method        Method call to ban.
  1005.      *    @param string $message       Overridden message.
  1006.      *    @access public
  1007.      */
  1008.     function expectNever($method$message '%s'{
  1009.         $this->expectMaximumCallCount($method0$message);
  1010.     }
  1011.  
  1012.     /**
  1013.      *    Convenience method for a single method
  1014.      *    call.
  1015.      *    @param string $method     Method call to track.
  1016.      *    @param array $args        Expected argument list or
  1017.      *                               false for any arguments.
  1018.      *    @param string $message    Overridden message.
  1019.      *    @access public
  1020.      */
  1021.     function expectOnce($method$args false$message '%s'{
  1022.         $this->expectCallCount($method1$message);
  1023.         if ($args !== false{
  1024.             $this->expect($method$args$message);
  1025.         }
  1026.     }
  1027.  
  1028.     /**
  1029.      *    Convenience method for requiring a method
  1030.      *    call.
  1031.      *    @param string $method       Method call to track.
  1032.      *    @param array $args          Expected argument list or
  1033.      *                                 false for any arguments.
  1034.      *    @param string $message      Overridden message.
  1035.      *    @access public
  1036.      */
  1037.     function expectAtLeastOnce($method$args false$message '%s'{
  1038.         $this->expectMinimumCallCount($method1$message);
  1039.         if ($args !== false{
  1040.             $this->expect($method$args$message);
  1041.         }
  1042.     }
  1043.     
  1044.     /**
  1045.      *    Sets up a trigger to throw an exception upon the
  1046.      *    method call.
  1047.      *    @param string $method     Method name to throw on.
  1048.      */
  1049.     function throwOn($method$exception false$args false{
  1050.         $this->dieOnNoMethod($method"throw on");
  1051.         $this->actions->register($method$args,
  1052.                 new SimpleThrower($exception $exception new Exception()));
  1053.     }
  1054.     
  1055.     /**
  1056.      *    Sets up a trigger to throw an exception upon the
  1057.      *    method call.
  1058.      */
  1059.     function throwAt($timing$method$exception false$args false{
  1060.         $this->dieOnNoMethod($method"throw at");
  1061.         $this->actions->registerAt($timing$method$args,
  1062.                 new SimpleThrower($exception $exception new Exception()));
  1063.     }
  1064.     
  1065.     /**
  1066.      *    Sets up a trigger to throw an error upon the
  1067.      *    method call.
  1068.      */
  1069.     function errorOn($method$error 'A mock error'$args false$severity E_USER_ERROR{
  1070.         $this->dieOnNoMethod($method"error on");
  1071.         $this->actions->register($method$argsnew SimpleErrorThrower($error$severity));
  1072.     }
  1073.     
  1074.     /**
  1075.      *    Sets up a trigger to throw an error upon the
  1076.      *    method call.
  1077.      */
  1078.     function errorAt($timing$method$error 'A mock error'$args false$severity E_USER_ERROR{
  1079.         $this->dieOnNoMethod($method"error at");
  1080.         $this->actions->registerAt($timing$method$argsnew SimpleErrorThrower($error$severity));
  1081.     }
  1082.  
  1083.     /**
  1084.      *    Receives event from unit test that the current
  1085.      *    test method has finished. Totals up the call
  1086.      *    counts and triggers a test assertion if a test
  1087.      *    is present for expected call counts.
  1088.      *    @param string $test_method      Current method name.
  1089.      *    @param SimpleTestCase $test     Test to send message to.
  1090.      *    @access public
  1091.      */
  1092.     function atTestEnd($test_method&$test{
  1093.         foreach ($this->expected_counts as $method => $expectation{
  1094.             $test->assert($expectation$this->getCallCount($method));
  1095.         }
  1096.         foreach ($this->max_counts as $method => $expectation{
  1097.             if ($expectation->test($this->getCallCount($method))) {
  1098.                 $test->assert($expectation$this->getCallCount($method));
  1099.             }
  1100.         }
  1101.     }
  1102.  
  1103.     /**
  1104.      *    Returns the expected value for the method name
  1105.      *    and checks expectations. Will generate any
  1106.      *    test assertions as a result of expectations
  1107.      *    if there is a test present.
  1108.      *    @param string $method       Name of method to simulate.
  1109.      *    @param array $args          Arguments as an array.
  1110.      *    @return mixed               Stored return.
  1111.      *    @access private
  1112.      */
  1113.     function &invoke($method$args{
  1114.         $method strtolower($method);
  1115.         $step $this->getCallCount($method);
  1116.         $this->addCall($method$args);
  1117.         $this->checkExpectations($method$args$step);
  1118.         $was $this->disableEStrict();
  1119.         try {
  1120.             $result &$this->emulateCall($method$args$step);
  1121.         catch (Exception $e{
  1122.             $this->restoreEStrict($was);
  1123.             throw $e;
  1124.         }
  1125.         $this->restoreEStrict($was);
  1126.         return $result;
  1127.     }
  1128.     
  1129.     /**
  1130.      *    Finds the return value matching the incoming
  1131.      *    arguments. If there is no matching value found
  1132.      *    then an error is triggered.
  1133.      *    @param string $method      Method name.
  1134.      *    @param array $args         Calling arguments.
  1135.      *    @param integer $step       Current position in the
  1136.      *                                call history.
  1137.      *    @return mixed              Stored return or other action.
  1138.      *    @access protected
  1139.      */
  1140.     protected function &emulateCall($method$args$step{
  1141.         return $this->actions->respond($step$method$args);
  1142.     }
  1143.  
  1144.     /**
  1145.      *    Tests the arguments against expectations.
  1146.      *    @param string $method        Method to check.
  1147.      *    @param array $args           Argument list to match.
  1148.      *    @param integer $timing       The position of this call
  1149.      *                                  in the call history.
  1150.      *    @access private
  1151.      */
  1152.     protected function checkExpectations($method$args$timing{
  1153.         $test $this->getCurrentTestCase();
  1154.         if (isset($this->max_counts[$method])) {
  1155.             if ($this->max_counts[$method]->test($timing 1)) {
  1156.                 $test->assert($this->max_counts[$method]$timing 1);
  1157.             }
  1158.         }
  1159.         if (isset($this->expected_args_at[$timing][$method])) {
  1160.             $test->assert(
  1161.                     $this->expected_args_at[$timing][$method],
  1162.                     $args,
  1163.                     "Mock method [$method] at [$timing] -> %s");
  1164.         elseif (isset($this->expected_args[$method])) {
  1165.             $test->assert(
  1166.                     $this->expected_args[$method],
  1167.                     $args,
  1168.                     "Mock method [$method] -> %s");
  1169.         }
  1170.     }
  1171.     
  1172.     private function disableEStrict({
  1173.         $was error_reporting();
  1174.         error_reporting($was ~E_STRICT);
  1175.         return $was;
  1176.     }
  1177.     
  1178.     private function restoreEStrict($was{
  1179.         error_reporting($was);
  1180.     }
  1181. }
  1182.  
  1183. /**
  1184.  *    Static methods only service class for code generation of
  1185.  *    mock objects.
  1186.  *    @package SimpleTest
  1187.  *    @subpackage MockObjects
  1188.  */
  1189. class Mock {
  1190.  
  1191.     /**
  1192.      *    Factory for mock object classes.
  1193.      *    @access public
  1194.      */
  1195.     function __construct({
  1196.         trigger_error('Mock factory methods are static.');
  1197.     }
  1198.  
  1199.     /**
  1200.      *    Clones a class' interface and creates a mock version
  1201.      *    that can have return values and expectations set.
  1202.      *    @param string $class         Class to clone.
  1203.      *    @param string $mock_class    New class name. Default is
  1204.      *                                  the old name with "Mock"
  1205.      *                                  prepended.
  1206.      *    @param array $methods        Additional methods to add beyond
  1207.      *                                  those in the cloned class. Use this
  1208.      *                                  to emulate the dynamic addition of
  1209.      *                                  methods in the cloned class or when
  1210.      *                                  the class hasn't been written yet.sta
  1211.      *    @access public
  1212.      */
  1213.     static function generate($class$mock_class false$methods false{
  1214.         $generator new MockGenerator($class$mock_class);
  1215.         return @$generator->generateSubclass($methods);
  1216.     }
  1217.  
  1218.     /**
  1219.      *    Generates a version of a class with selected
  1220.      *    methods mocked only. Inherits the old class
  1221.      *    and chains the mock methods of an aggregated
  1222.      *    mock object.
  1223.      *    @param string $class            Class to clone.
  1224.      *    @param string $mock_class       New class name.
  1225.      *    @param array $methods           Methods to be overridden
  1226.      *                                     with mock versions.
  1227.      *    @access public
  1228.      */
  1229.     static function generatePartial($class$mock_class$methods{
  1230.         $generator new MockGenerator($class$mock_class);
  1231.         return @$generator->generatePartial($methods);
  1232.     }
  1233.  
  1234.     /**
  1235.      *    Uses a stack trace to find the line of an assertion.
  1236.      *    @access public
  1237.      */
  1238.     static function getExpectationLine({
  1239.         $trace new SimpleStackTrace(array('expect'));
  1240.         return $trace->traceMethod();
  1241.     }
  1242. }
  1243.  
  1244. /**
  1245.  *    Service class for code generation of mock objects.
  1246.  *    @package SimpleTest
  1247.  *    @subpackage MockObjects
  1248.  */
  1249. class MockGenerator {
  1250.     private $class;
  1251.     private $mock_class;
  1252.     private $mock_base;
  1253.     private $reflection;
  1254.  
  1255.     /**
  1256.      *    Builds initial reflection object.
  1257.      *    @param string $class        Class to be mocked.
  1258.      *    @param string $mock_class   New class with identical interface,
  1259.      *                                 but no behaviour.
  1260.      */
  1261.     function __construct($class$mock_class{
  1262.         $this->class $class;
  1263.         $this->mock_class $mock_class;
  1264.         if ($this->mock_class{
  1265.             $this->mock_class 'Mock' $this->class;
  1266.         }
  1267.         $this->mock_base SimpleTest::getMockBaseClass();
  1268.         $this->reflection new SimpleReflection($this->class);
  1269.     }
  1270.  
  1271.     /**
  1272.      *    Clones a class' interface and creates a mock version
  1273.      *    that can have return values and expectations set.
  1274.      *    @param array $methods        Additional methods to add beyond
  1275.      *                                  those in th cloned class. Use this
  1276.      *                                  to emulate the dynamic addition of
  1277.      *                                  methods in the cloned class or when
  1278.      *                                  the class hasn't been written yet.
  1279.      *    @access public
  1280.      */
  1281.     function generate($methods{
  1282.         if ($this->reflection->classOrInterfaceExists()) {
  1283.             return false;
  1284.         }
  1285.         $mock_reflection new SimpleReflection($this->mock_class);
  1286.         if ($mock_reflection->classExistsSansAutoload()) {
  1287.             return false;
  1288.         }
  1289.         $code $this->createClassCode($methods $methods array());
  1290.         return eval("$code return \$code;");
  1291.     }
  1292.     
  1293.     /**
  1294.      *    Subclasses a class and overrides every method with a mock one
  1295.      *    that can have return values and expectations set. Chains
  1296.      *    to an aggregated SimpleMock.
  1297.      *    @param array $methods        Additional methods to add beyond
  1298.      *                                  those in the cloned class. Use this
  1299.      *                                  to emulate the dynamic addition of
  1300.      *                                  methods in the cloned class or when
  1301.      *                                  the class hasn't been written yet.
  1302.      *    @access public
  1303.      */
  1304.     function generateSubclass($methods{
  1305.         if ($this->reflection->classOrInterfaceExists()) {
  1306.             return false;
  1307.         }
  1308.         $mock_reflection new SimpleReflection($this->mock_class);
  1309.         if ($mock_reflection->classExistsSansAutoload()) {
  1310.             return false;
  1311.         }
  1312.         if ($this->reflection->isInterface(|| $this->reflection->hasFinal()) {
  1313.             $code $this->createClassCode($methods $methods array());
  1314.             return eval("$code return \$code;");
  1315.         else {
  1316.             $code $this->createSubclassCode($methods $methods array());
  1317.             return eval("$code return \$code;");
  1318.         }
  1319.     }
  1320.  
  1321.     /**
  1322.      *    Generates a version of a class with selected
  1323.      *    methods mocked only. Inherits the old class
  1324.      *    and chains the mock methods of an aggregated
  1325.      *    mock object.
  1326.      *    @param array $methods           Methods to be overridden
  1327.      *                                     with mock versions.
  1328.      *    @access public
  1329.      */
  1330.     function generatePartial($methods{
  1331.         if ($this->reflection->classExists($this->class)) {
  1332.             return false;
  1333.         }
  1334.         $mock_reflection new SimpleReflection($this->mock_class);
  1335.         if ($mock_reflection->classExistsSansAutoload()) {
  1336.             trigger_error('Partial mock class [' $this->mock_class '] already exists');
  1337.             return false;
  1338.         }
  1339.         $code $this->extendClassCode($methods);
  1340.         return eval("$code return \$code;");
  1341.     }
  1342.  
  1343.     /**
  1344.      *    The new mock class code as a string.
  1345.      *    @param array $methods          Additional methods.
  1346.      *    @return string                 Code for new mock class.
  1347.      *    @access private
  1348.      */
  1349.     protected function createClassCode($methods{
  1350.         $implements '';
  1351.         $interfaces $this->reflection->getInterfaces();
  1352.         if (function_exists('spl_classes')) {
  1353.             $interfaces array_diff($interfacesarray('Traversable'));
  1354.         }
  1355.         if (count($interfaces0{
  1356.             $implements 'implements ' implode(', '$interfaces);
  1357.         }
  1358.         $code "class " $this->mock_class " extends " $this->mock_base " $implements {\n";
  1359.         $code .= "    function " $this->mock_class "() {\n";
  1360.         $code .= "        \$this->" $this->mock_base "();\n";
  1361.         $code .= "    }\n";
  1362.         if (in_array('__construct'$this->reflection->getMethods())) {
  1363.             $code .= "    function __construct() {\n";
  1364.             $code .= "        \$this->" $this->mock_base "();\n";
  1365.             $code .= "    }\n";
  1366.         }
  1367.         $code .= $this->createHandlerCode($methods);
  1368.         $code .= "}\n";
  1369.         return $code;
  1370.     }
  1371.  
  1372.     /**
  1373.      *    The new mock class code as a string. The mock will
  1374.      *    be a subclass of the original mocked class.
  1375.      *    @param array $methods          Additional methods.
  1376.      *    @return string                 Code for new mock class.
  1377.      *    @access private
  1378.      */
  1379.     protected function createSubclassCode($methods{
  1380.         $code  "class " $this->mock_class " extends " $this->class " {\n";
  1381.         $code .= "    public \$mock;\n";
  1382.         $code .= $this->addMethodList(array_merge($methods$this->reflection->getMethods()));
  1383.         $code .= "\n";
  1384.         $code .= "    function " $this->mock_class "() {\n";
  1385.         $code .= "        \$this->mock = new " $this->mock_base "();\n";
  1386.         $code .= "        \$this->mock->disableExpectationNameChecks();\n";
  1387.         $code .= "    }\n";
  1388.         $code .= $this->chainMockReturns();
  1389.         $code .= $this->chainMockExpectations();
  1390.         $code .= $this->chainThrowMethods();
  1391.         $code .= $this->overrideMethods($this->reflection->getMethods());
  1392.         $code .= $this->createNewMethodCode($methods);
  1393.         $code .= "}\n";
  1394.         return $code;
  1395.     }
  1396.  
  1397.     /**
  1398.      *    The extension class code as a string. The class
  1399.      *    composites a mock object and chains mocked methods
  1400.      *    to it.
  1401.      *    @param array  $methods       Mocked methods.
  1402.      *    @return string               Code for a new class.
  1403.      *    @access private
  1404.      */
  1405.     protected function extendClassCode($methods{
  1406.         $code  "class " $this->mock_class " extends " $this->class " {\n";
  1407.         $code .= "    protected \$mock;\n";
  1408.         $code .= $this->addMethodList($methods);
  1409.         $code .= "\n";
  1410.         $code .= "    function " $this->mock_class "() {\n";
  1411.         $code .= "        \$this->mock = new " $this->mock_base "();\n";
  1412.         $code .= "        \$this->mock->disableExpectationNameChecks();\n";
  1413.         $code .= "    }\n";
  1414.         $code .= $this->chainMockReturns();
  1415.         $code .= $this->chainMockExpectations();
  1416.         $code .= $this->chainThrowMethods();
  1417.         $code .= $this->overrideMethods($methods);
  1418.         $code .= "}\n";
  1419.         return $code;
  1420.     }
  1421.  
  1422.     /**
  1423.      *    Creates code within a class to generate replaced
  1424.      *    methods. All methods call the invoke() handler
  1425.      *    with the method name and the arguments in an
  1426.      *    array.
  1427.      *    @param array $methods    Additional methods.
  1428.      *    @access private
  1429.      */
  1430.     protected function createHandlerCode($methods{
  1431.         $code '';
  1432.         $methods array_merge($methods$this->reflection->getMethods());
  1433.         foreach ($methods as $method{
  1434.             if ($this->isConstructor($method)) {
  1435.                 continue;
  1436.             }
  1437.             $mock_reflection new SimpleReflection($this->mock_base);
  1438.             if (in_array($method$mock_reflection->getMethods())) {
  1439.                 continue;
  1440.             }
  1441.             $code .= "    " $this->reflection->getSignature($method" {\n";
  1442.             $code .= "        \$args = func_get_args();\n";
  1443.             $code .= "        \$result = &\$this->invoke(\"$method\", \$args);\n";
  1444.             $code .= "        return \$result;\n";
  1445.             $code .= "    }\n";
  1446.         }
  1447.         return $code;
  1448.     }
  1449.  
  1450.     /**
  1451.      *    Creates code within a class to generate a new
  1452.      *    methods. All methods call the invoke() handler
  1453.      *    on the internal mock with the method name and
  1454.      *    the arguments in an array.
  1455.      *    @param array $methods    Additional methods.
  1456.      *    @access private
  1457.      */
  1458.     protected function createNewMethodCode($methods{
  1459.         $code '';
  1460.         foreach ($methods as $method{
  1461.             if ($this->isConstructor($method)) {
  1462.                 continue;
  1463.             }
  1464.             $mock_reflection new SimpleReflection($this->mock_base);
  1465.             if (in_array($method$mock_reflection->getMethods())) {
  1466.                 continue;
  1467.             }
  1468.             $code .= "    " $this->reflection->getSignature($method" {\n";
  1469.             $code .= "        \$args = func_get_args();\n";
  1470.             $code .= "        \$result = &\$this->mock->invoke(\"$method\", \$args);\n";
  1471.             $code .= "        return \$result;\n";
  1472.             $code .= "    }\n";
  1473.         }
  1474.         return $code;
  1475.     }
  1476.  
  1477.     /**
  1478.      *    Tests to see if a special PHP method is about to
  1479.      *    be stubbed by mistake.
  1480.      *    @param string $method    Method name.
  1481.      *    @return boolean          True if special.
  1482.      *    @access private
  1483.      */
  1484.     protected function isConstructor($method{
  1485.         return in_array(
  1486.                 strtolower($method),
  1487.                 array('__construct''__destruct'));
  1488.     }
  1489.  
  1490.     /**
  1491.      *    Creates a list of mocked methods for error checking.
  1492.      *    @param array $methods       Mocked methods.
  1493.      *    @return string              Code for a method list.
  1494.      *    @access private
  1495.      */
  1496.     protected function addMethodList($methods{
  1497.         return "    protected \$mocked_methods = array('" .
  1498.                 implode("', '"array_map('strtolower'$methods)) .
  1499.                 "');\n";
  1500.     }
  1501.  
  1502.     /**
  1503.      *    Creates code to abandon the expectation if not mocked.
  1504.      *    @param string $alias       Parameter name of method name.
  1505.      *    @return string             Code for bail out.
  1506.      *    @access private
  1507.      */
  1508.     protected function bailOutIfNotMocked($alias{
  1509.         $code  "        if (! in_array(strtolower($alias), \$this->mocked_methods)) {\n";
  1510.         $code .= "            trigger_error(\"Method [$alias] is not mocked\");\n";
  1511.         $code .= "            \$null = null;\n";
  1512.         $code .= "            return \$null;\n";
  1513.         $code .= "        }\n";
  1514.         return $code;
  1515.     }
  1516.  
  1517.     /**
  1518.      *    Creates source code for chaining to the composited
  1519.      *    mock object.
  1520.      *    @return string           Code for mock set up.
  1521.      *    @access private
  1522.      */
  1523.     protected function chainMockReturns({
  1524.         $code  "    function returns(\$method, \$value, \$args = false) {\n";
  1525.         $code .= $this->bailOutIfNotMocked("\$method");
  1526.         $code .= "        \$this->mock->returns(\$method, \$value, \$args);\n";
  1527.         $code .= "    }\n";
  1528.         $code .= "    function returnsAt(\$timing, \$method, \$value, \$args = false) {\n";
  1529.         $code .= $this->bailOutIfNotMocked("\$method");
  1530.         $code .= "        \$this->mock->returnsAt(\$timing, \$method, \$value, \$args);\n";
  1531.         $code .= "    }\n";
  1532.         $code .= "    function returnsByValue(\$method, \$value, \$args = false) {\n";
  1533.         $code .= $this->bailOutIfNotMocked("\$method");
  1534.         $code .= "        \$this->mock->setReturnValue(\$method, \$value, \$args);\n";
  1535.         $code .= "    }\n";
  1536.         $code .= "    function returnsByValueAt(\$timing, \$method, \$value, \$args = false) {\n";
  1537.         $code .= $this->bailOutIfNotMocked("\$method");
  1538.         $code .= "        \$this->mock->setReturnValueAt(\$timing, \$method, \$value, \$args);\n";
  1539.         $code .= "    }\n";
  1540.         $code .= "    function returnsByReference(\$method, &\$ref, \$args = false) {\n";
  1541.         $code .= $this->bailOutIfNotMocked("\$method");
  1542.         $code .= "        \$this->mock->setReturnReference(\$method, \$ref, \$args);\n";
  1543.         $code .= "    }\n";
  1544.         $code .= "    function returnsByReferenceAt(\$timing, \$method, &\$ref, \$args = false) {\n";
  1545.         $code .= $this->bailOutIfNotMocked("\$method");
  1546.         $code .= "        \$this->mock->setReturnReferenceAt(\$timing, \$method, \$ref, \$args);\n";
  1547.         $code .= "    }\n";
  1548.         $code .= "    function setReturnValue(\$method, \$value, \$args = false) {\n";
  1549.         $code .= $this->bailOutIfNotMocked("\$method");
  1550.         $code .= "        \$this->mock->setReturnValue(\$method, \$value, \$args);\n";
  1551.         $code .= "    }\n";
  1552.         $code .= "    function setReturnValueAt(\$timing, \$method, \$value, \$args = false) {\n";
  1553.         $code .= $this->bailOutIfNotMocked("\$method");
  1554.         $code .= "        \$this->mock->setReturnValueAt(\$timing, \$method, \$value, \$args);\n";
  1555.         $code .= "    }\n";
  1556.         $code .= "    function setReturnReference(\$method, &\$ref, \$args = false) {\n";
  1557.         $code .= $this->bailOutIfNotMocked("\$method");
  1558.         $code .= "        \$this->mock->setReturnReference(\$method, \$ref, \$args);\n";
  1559.         $code .= "    }\n";
  1560.         $code .= "    function setReturnReferenceAt(\$timing, \$method, &\$ref, \$args = false) {\n";
  1561.         $code .= $this->bailOutIfNotMocked("\$method");
  1562.         $code .= "        \$this->mock->setReturnReferenceAt(\$timing, \$method, \$ref, \$args);\n";
  1563.         $code .= "    }\n";
  1564.         return $code;
  1565.     }
  1566.  
  1567.     /**
  1568.      *    Creates source code for chaining to an aggregated
  1569.      *    mock object.
  1570.      *    @return string                 Code for expectations.
  1571.      *    @access private
  1572.      */
  1573.     protected function chainMockExpectations({
  1574.         $code  "    function expect(\$method, \$args = false, \$msg = '%s') {\n";
  1575.         $code .= $this->bailOutIfNotMocked("\$method");
  1576.         $code .= "        \$this->mock->expect(\$method, \$args, \$msg);\n";
  1577.         $code .= "    }\n";
  1578.         $code .= "    function expectAt(\$timing, \$method, \$args = false, \$msg = '%s') {\n";
  1579.         $code .= $this->bailOutIfNotMocked("\$method");
  1580.         $code .= "        \$this->mock->expectAt(\$timing, \$method, \$args, \$msg);\n";
  1581.         $code .= "    }\n";
  1582.         $code .= "    function expectCallCount(\$method, \$count) {\n";
  1583.         $code .= $this->bailOutIfNotMocked("\$method");
  1584.         $code .= "        \$this->mock->expectCallCount(\$method, \$count, \$msg = '%s');\n";
  1585.         $code .= "    }\n";
  1586.         $code .= "    function expectMaximumCallCount(\$method, \$count, \$msg = '%s') {\n";
  1587.         $code .= $this->bailOutIfNotMocked("\$method");
  1588.         $code .= "        \$this->mock->expectMaximumCallCount(\$method, \$count, \$msg = '%s');\n";
  1589.         $code .= "    }\n";
  1590.         $code .= "    function expectMinimumCallCount(\$method, \$count, \$msg = '%s') {\n";
  1591.         $code .= $this->bailOutIfNotMocked("\$method");
  1592.         $code .= "        \$this->mock->expectMinimumCallCount(\$method, \$count, \$msg = '%s');\n";
  1593.         $code .= "    }\n";
  1594.         $code .= "    function expectNever(\$method) {\n";
  1595.         $code .= $this->bailOutIfNotMocked("\$method");
  1596.         $code .= "        \$this->mock->expectNever(\$method);\n";
  1597.         $code .= "    }\n";
  1598.         $code .= "    function expectOnce(\$method, \$args = false, \$msg = '%s') {\n";
  1599.         $code .= $this->bailOutIfNotMocked("\$method");
  1600.         $code .= "        \$this->mock->expectOnce(\$method, \$args, \$msg);\n";
  1601.         $code .= "    }\n";
  1602.         $code .= "    function expectAtLeastOnce(\$method, \$args = false, \$msg = '%s') {\n";
  1603.         $code .= $this->bailOutIfNotMocked("\$method");
  1604.         $code .= "        \$this->mock->expectAtLeastOnce(\$method, \$args, \$msg);\n";
  1605.         $code .= "    }\n";
  1606.         return $code;
  1607.     }
  1608.     
  1609.     /**
  1610.      *    Adds code for chaining the throw methods.
  1611.      *    @return string           Code for chains.
  1612.      *    @access private
  1613.      */
  1614.     protected function chainThrowMethods({
  1615.         $code  "    function throwOn(\$method, \$exception = false, \$args = false) {\n";
  1616.         $code .= $this->bailOutIfNotMocked("\$method");
  1617.         $code .= "        \$this->mock->throwOn(\$method, \$exception, \$args);\n";
  1618.         $code .= "    }\n";
  1619.         $code .= "    function throwAt(\$timing, \$method, \$exception = false, \$args = false) {\n";
  1620.         $code .= $this->bailOutIfNotMocked("\$method");
  1621.         $code .= "        \$this->mock->throwAt(\$timing, \$method, \$exception, \$args);\n";
  1622.         $code .= "    }\n";
  1623.         $code .= "    function errorOn(\$method, \$error = 'A mock error', \$args = false, \$severity = E_USER_ERROR) {\n";
  1624.         $code .= $this->bailOutIfNotMocked("\$method");
  1625.         $code .= "        \$this->mock->errorOn(\$method, \$error, \$args, \$severity);\n";
  1626.         $code .= "    }\n";
  1627.         $code .= "    function errorAt(\$timing, \$method, \$error = 'A mock error', \$args = false, \$severity = E_USER_ERROR) {\n";
  1628.         $code .= $this->bailOutIfNotMocked("\$method");
  1629.         $code .= "        \$this->mock->errorAt(\$timing, \$method, \$error, \$args, \$severity);\n";
  1630.         $code .= "    }\n";
  1631.         return $code;
  1632.     }
  1633.  
  1634.     /**
  1635.      *    Creates source code to override a list of methods
  1636.      *    with mock versions.
  1637.      *    @param array $methods    Methods to be overridden
  1638.      *                              with mock versions.
  1639.      *    @return string           Code for overridden chains.
  1640.      *    @access private
  1641.      */
  1642.     protected function overrideMethods($methods{
  1643.         $code "";
  1644.         foreach ($methods as $method{
  1645.             if ($this->isConstructor($method)) {
  1646.                 continue;
  1647.             }
  1648.             $code .= "    " $this->reflection->getSignature($method" {\n";
  1649.             $code .= "        \$args = func_get_args();\n";
  1650.             $code .= "        \$result = &\$this->mock->invoke(\"$method\", \$args);\n";
  1651.             $code .= "        return \$result;\n";
  1652.             $code .= "    }\n";
  1653.         }
  1654.         return $code;
  1655.     }
  1656. }
  1657. ?>

Documentation generated on Thu, 01 Oct 2009 20:55:11 -0500 by phpDocumentor 1.4.2