Fixing file upload params ($_FILES) normalization. Closes #75
[akelos.git] / vendor / simpletest / mock_objects.php
blob651d28517762e56973d6c41296f2dbba017c8691
1 <?php
2 /**
3 * base include file for SimpleTest
4 * @package SimpleTest
5 * @subpackage MockObjects
6 * @version $Id: mock_objects.php,v 1.90 2006/02/05 19:35:31 lastcraft Exp $
7 */
9 /**#@+
10 * include SimpleTest files
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');
20 /**#@-*/
22 /**
23 * Default character simpletest will substitute for any value
25 if (! defined('MOCK_ANYTHING')) {
26 define('MOCK_ANYTHING', '*');
29 /**
30 * A wildcard expectation always matches.
31 * @package SimpleTest
32 * @subpackage MockObjects
34 class AnythingExpectation extends SimpleExpectation {
36 /**
37 * Tests the expectation. Always true.
38 * @param mixed $compare Ignored.
39 * @return boolean True.
40 * @access public
42 function test($compare) {
43 return true;
46 /**
47 * Returns a human readable test message.
48 * @param mixed $compare Comparison value.
49 * @return string Description of success
50 * or failure.
51 * @access public
53 function testMessage($compare) {
54 $dumper = &$this->_getDumper();
55 return 'Anything always matches [' . $dumper->describeValue($compare) . ']';
59 /**
60 * Parameter comparison assertion.
61 * @package SimpleTest
62 * @subpackage MockObjects
64 class ParametersExpectation extends SimpleExpectation {
65 var $_expected;
67 /**
68 * Sets the expected parameter list.
69 * @param array $parameters Array of parameters including
70 * those that are wildcarded.
71 * If the value is not an array
72 * then it is considered to match any.
73 * @param mixed $wildcard Any parameter matching this
74 * will always match.
75 * @param string $message Customised message on failure.
76 * @access public
78 function ParametersExpectation($expected = false, $message = '%s') {
79 $this->SimpleExpectation($message);
80 $this->_expected = $expected;
83 /**
84 * Tests the assertion. True if correct.
85 * @param array $parameters Comparison values.
86 * @return boolean True if correct.
87 * @access public
89 function test($parameters) {
90 if (! is_array($this->_expected)) {
91 return true;
93 if (count($this->_expected) != count($parameters)) {
94 return false;
96 for ($i = 0; $i < count($this->_expected); $i++) {
97 if (! $this->_testParameter($parameters[$i], $this->_expected[$i])) {
98 return false;
101 return true;
105 * Tests an individual parameter.
106 * @param mixed $parameter Value to test.
107 * @param mixed $expected Comparison value.
108 * @return boolean True if expectation
109 * fulfilled.
110 * @access private
112 function _testParameter($parameter, $expected) {
113 $comparison = $this->_coerceToExpectation($expected);
114 return $comparison->test($parameter);
118 * Returns a human readable test message.
119 * @param array $comparison Incoming parameter list.
120 * @return string Description of success
121 * or failure.
122 * @access public
124 function testMessage($parameters) {
125 if ($this->test($parameters)) {
126 return "Expectation of " . count($this->_expected) .
127 " arguments of [" . $this->_renderArguments($this->_expected) .
128 "] is correct";
129 } else {
130 return $this->_describeDifference($this->_expected, $parameters);
135 * Message to display if expectation differs from
136 * the parameters actually received.
137 * @param array $expected Expected parameters as list.
138 * @param array $parameters Actual parameters received.
139 * @return string Description of difference.
140 * @access private
142 function _describeDifference($expected, $parameters) {
143 if (count($expected) != count($parameters)) {
144 return "Expected " . count($expected) .
145 " arguments of [" . $this->_renderArguments($expected) .
146 "] but got " . count($parameters) .
147 " arguments of [" . $this->_renderArguments($parameters) . "]";
149 $messages = array();
150 for ($i = 0; $i < count($expected); $i++) {
151 $comparison = $this->_coerceToExpectation($expected[$i]);
152 if (! $comparison->test($parameters[$i])) {
153 $messages[] = "parameter " . ($i + 1) . " with [" .
154 $comparison->overlayMessage($parameters[$i]) . "]";
157 return "Parameter expectation differs at " . implode(" and ", $messages);
161 * Creates an identical expectation if the
162 * object/value is not already some type
163 * of expectation.
164 * @param mixed $expected Expected value.
165 * @return SimpleExpectation Expectation object.
166 * @access private
168 function _coerceToExpectation($expected) {
169 if (SimpleExpectation::isExpectation($expected)) {
170 return $expected;
172 return new IdenticalExpectation($expected);
176 * Renders the argument list as a string for
177 * messages.
178 * @param array $args Incoming arguments.
179 * @return string Simple description of type and value.
180 * @access private
182 function _renderArguments($args) {
183 $descriptions = array();
184 if (is_array($args)) {
185 foreach ($args as $arg) {
186 $dumper = &new SimpleDumper();
187 $descriptions[] = $dumper->describeValue($arg);
190 return implode(', ', $descriptions);
195 * Confirms that the number of calls on a method is as expected.
197 class CallCountExpectation extends SimpleExpectation {
198 var $_method;
199 var $_count;
202 * Stashes the method and expected count for later
203 * reporting.
204 * @param string $method Name of method to confirm against.
205 * @param integer $count Expected number of calls.
206 * @param string $message Custom error message.
208 function CallCountExpectation($method, $count, $message = '%s') {
209 $this->_method = $method;
210 $this->_count = $count;
211 $this->SimpleExpectation($message);
215 * Tests the assertion. True if correct.
216 * @param integer $compare Measured call count.
217 * @return boolean True if expected.
218 * @access public
220 function test($compare) {
221 return ($this->_count == $compare);
225 * Reports the comparison.
226 * @param integer $compare Measured call count.
227 * @return string Message to show.
228 * @access public
230 function testMessage($compare) {
231 return 'Expected call count for [' . $this->_method .
232 '] was [' . $this->_count .
233 '] got [' . $compare . ']';
238 * Confirms that the number of calls on a method is as expected.
240 class MinimumCallCountExpectation extends SimpleExpectation {
241 var $_method;
242 var $_count;
245 * Stashes the method and expected count for later
246 * reporting.
247 * @param string $method Name of method to confirm against.
248 * @param integer $count Minimum number of calls.
249 * @param string $message Custom error message.
251 function MinimumCallCountExpectation($method, $count, $message = '%s') {
252 $this->_method = $method;
253 $this->_count = $count;
254 $this->SimpleExpectation($message);
258 * Tests the assertion. True if correct.
259 * @param integer $compare Measured call count.
260 * @return boolean True if enough.
261 * @access public
263 function test($compare) {
264 return ($this->_count <= $compare);
268 * Reports the comparison.
269 * @param integer $compare Measured call count.
270 * @return string Message to show.
271 * @access public
273 function testMessage($compare) {
274 return 'Minimum call count for [' . $this->_method .
275 '] was [' . $this->_count .
276 '] got [' . $compare . ']';
281 * Confirms that the number of calls on a method is as expected.
283 class MaximumCallCountExpectation extends SimpleExpectation {
284 var $_method;
285 var $_count;
288 * Stashes the method and expected count for later
289 * reporting.
290 * @param string $method Name of method to confirm against.
291 * @param integer $count Minimum number of calls.
292 * @param string $message Custom error message.
294 function MaximumCallCountExpectation($method, $count, $message = '%s') {
295 $this->_method = $method;
296 $this->_count = $count;
297 $this->SimpleExpectation($message);
301 * Tests the assertion. True if correct.
302 * @param integer $compare Measured call count.
303 * @return boolean True if not over.
304 * @access public
306 function test($compare) {
307 return ($this->_count >= $compare);
311 * Reports the comparison.
312 * @param integer $compare Measured call count.
313 * @return string Message to show.
314 * @access public
316 function testMessage($compare) {
317 return 'Maximum call count for [' . $this->_method .
318 '] was [' . $this->_count .
319 '] got [' . $compare . ']';
324 * Retrieves values and references by searching the
325 * parameter lists until a match is found.
326 * @package SimpleTest
327 * @subpackage MockObjects
329 class CallMap {
330 var $_map;
333 * Creates an empty call map.
334 * @access public
336 function CallMap() {
337 $this->_map = array();
341 * Stashes a value against a method call.
342 * @param array $parameters Arguments including wildcards.
343 * @param mixed $value Value copied into the map.
344 * @access public
346 function addValue($parameters, $value) {
347 $this->addReference($parameters, $value);
351 * Stashes a reference against a method call.
352 * @param array $parameters Array of arguments (including wildcards).
353 * @param mixed $reference Array reference placed in the map.
354 * @access public
356 function addReference($parameters, &$reference) {
357 $place = count($this->_map);
358 $this->_map[$place] = array();
359 $this->_map[$place]["params"] = new ParametersExpectation($parameters);
360 $this->_map[$place]["content"] = &$reference;
364 * Searches the call list for a matching parameter
365 * set. Returned by reference.
366 * @param array $parameters Parameters to search by
367 * without wildcards.
368 * @return object Object held in the first matching
369 * slot, otherwise null.
370 * @access public
372 function &findFirstMatch($parameters) {
373 $slot = $this->_findFirstSlot($parameters);
374 if (!isset($slot)) {
375 $null = null;
376 return $null;
378 return $slot["content"];
382 * Searches the call list for a matching parameter
383 * set. True if successful.
384 * @param array $parameters Parameters to search by
385 * without wildcards.
386 * @return boolean True if a match is present.
387 * @access public
389 function isMatch($parameters) {
390 return ($this->_findFirstSlot($parameters) != null);
394 * Searches the map for a matching item.
395 * @param array $parameters Parameters to search by
396 * without wildcards.
397 * @return array Reference to slot or null.
398 * @access private
400 function &_findFirstSlot($parameters) {
401 $count = count($this->_map);
402 for ($i = 0; $i < $count; $i++) {
403 if ($this->_map[$i]["params"]->test($parameters)) {
404 return $this->_map[$i];
407 $null = null;
408 return $null;
413 * An empty collection of methods that can have their
414 * return values set and expectations made of the
415 * calls upon them. The mock will assert the
416 * expectations against it's attached test case in
417 * addition to the server stub behaviour.
418 * @package SimpleTest
419 * @subpackage MockObjects
421 class SimpleMock {
422 var $_wildcard = MOCK_ANYTHING;
423 var $_is_strict = true;
424 var $_returns;
425 var $_return_sequence;
426 var $_call_counts;
427 var $_expected_counts;
428 var $_max_counts;
429 var $_expected_args;
430 var $_expected_args_at;
433 * Creates an empty return list and expectation list.
434 * All call counts are set to zero.
435 * @param SimpleTestCase $test Test case to test expectations in.
436 * @param mixed $wildcard Parameter matching wildcard.
437 * @param boolean $is_strict Enables method name checks on
438 * expectations.
440 function SimpleMock() {
441 $this->_returns = array();
442 $this->_return_sequence = array();
443 $this->_call_counts = array();
444 $test = &$this->_getCurrentTestCase();
445 $test->tell($this);
446 $this->_expected_counts = array();
447 $this->_max_counts = array();
448 $this->_expected_args = array();
449 $this->_expected_args_at = array();
453 * Disables a name check when setting expectations.
454 * This hack is needed for the partial mocks.
455 * @access public
457 function disableExpectationNameChecks() {
458 $this->_is_strict = false;
462 * Changes the default wildcard object.
463 * @param mixed $wildcard Parameter matching wildcard.
464 * @access public
466 function setWildcard($wildcard) {
467 $this->_wildcard = $wildcard;
471 * Finds currently running test.
472 * @return SimpeTestCase Current test case.
473 * @access protected
475 function &_getCurrentTestCase() {
476 return SimpleTest::getCurrent();
480 * Die if bad arguments array is passed
481 * @param mixed $args The arguments value to be checked.
482 * @param string $task Description of task attempt.
483 * @return boolean Valid arguments
484 * @access private
486 function _checkArgumentsIsArray($args, $task) {
487 if (! is_array($args)) {
488 trigger_error(
489 "Cannot $task as \$args parameter is not an array",
490 E_USER_ERROR);
495 * Triggers a PHP error if the method is not part
496 * of this object.
497 * @param string $method Name of method.
498 * @param string $task Description of task attempt.
499 * @access protected
501 function _dieOnNoMethod($method, $task) {
502 if ($this->_is_strict && ! method_exists($this, $method)) {
503 trigger_error(
504 "Cannot $task as no ${method}() in class " . get_class($this),
505 E_USER_ERROR);
510 * Replaces wildcard matches with wildcard
511 * expectations in the argument list.
512 * @param array $args Raw argument list.
513 * @return array Argument list with
514 * expectations.
515 * @access private
517 function _replaceWildcards($args) {
518 if ($args === false) {
519 return false;
521 for ($i = 0; $i < count($args); $i++) {
522 if ($args[$i] === $this->_wildcard) {
523 $args[$i] = new AnythingExpectation();
526 return $args;
530 * Adds one to the call count of a method.
531 * @param string $method Method called.
532 * @param array $args Arguments as an array.
533 * @access protected
535 function _addCall($method, $args) {
536 if (!isset($this->_call_counts[$method])) {
537 $this->_call_counts[$method] = 0;
539 $this->_call_counts[$method]++;
543 * Fetches the call count of a method so far.
544 * @param string $method Method name called.
545 * @return Number of calls so far.
546 * @access public
548 function getCallCount($method) {
549 $this->_dieOnNoMethod($method, "get call count");
550 $method = strtolower($method);
551 if (! isset($this->_call_counts[$method])) {
552 return 0;
554 return $this->_call_counts[$method];
558 * Sets a return for a parameter list that will
559 * be passed by value for all calls to this method.
560 * @param string $method Method name.
561 * @param mixed $value Result of call passed by value.
562 * @param array $args List of parameters to match
563 * including wildcards.
564 * @access public
566 function setReturnValue($method, $value, $args = false) {
567 $this->_dieOnNoMethod($method, "set return value");
568 $args = $this->_replaceWildcards($args);
569 $method = strtolower($method);
570 if (! isset($this->_returns[$method])) {
571 $this->_returns[$method] = new CallMap();
573 $this->_returns[$method]->addValue($args, $value);
577 * Sets a return for a parameter list that will
578 * be passed by value only when the required call count
579 * is reached.
580 * @param integer $timing Number of calls in the future
581 * to which the result applies. If
582 * not set then all calls will return
583 * the value.
584 * @param string $method Method name.
585 * @param mixed $value Result of call passed by value.
586 * @param array $args List of parameters to match
587 * including wildcards.
588 * @access public
590 function setReturnValueAt($timing, $method, $value, $args = false) {
591 $this->_dieOnNoMethod($method, "set return value sequence");
592 $args = $this->_replaceWildcards($args);
593 $method = strtolower($method);
594 if (! isset($this->_return_sequence[$method])) {
595 $this->_return_sequence[$method] = array();
597 if (! isset($this->_return_sequence[$method][$timing])) {
598 $this->_return_sequence[$method][$timing] = new CallMap();
600 $this->_return_sequence[$method][$timing]->addValue($args, $value);
604 * Sets a return for a parameter list that will
605 * be passed by reference for all calls.
606 * @param string $method Method name.
607 * @param mixed $reference Result of the call will be this object.
608 * @param array $args List of parameters to match
609 * including wildcards.
610 * @access public
612 function setReturnReference($method, &$reference, $args = false) {
613 $this->_dieOnNoMethod($method, "set return reference");
614 $args = $this->_replaceWildcards($args);
615 $method = strtolower($method);
616 if (! isset($this->_returns[$method])) {
617 $this->_returns[$method] = new CallMap();
619 $this->_returns[$method]->addReference($args, $reference);
623 * Sets a return for a parameter list that will
624 * be passed by value only when the required call count
625 * is reached.
626 * @param integer $timing Number of calls in the future
627 * to which the result applies. If
628 * not set then all calls will return
629 * the value.
630 * @param string $method Method name.
631 * @param mixed $reference Result of the call will be this object.
632 * @param array $args List of parameters to match
633 * including wildcards.
634 * @access public
636 function setReturnReferenceAt($timing, $method, &$reference, $args = false) {
637 $this->_dieOnNoMethod($method, "set return reference sequence");
638 $args = $this->_replaceWildcards($args);
639 $method = strtolower($method);
640 if (! isset($this->_return_sequence[$method])) {
641 $this->_return_sequence[$method] = array();
643 if (! isset($this->_return_sequence[$method][$timing])) {
644 $this->_return_sequence[$method][$timing] = new CallMap();
646 $this->_return_sequence[$method][$timing]->addReference($args, $reference);
650 * Sets up an expected call with a set of
651 * expected parameters in that call. All
652 * calls will be compared to these expectations
653 * regardless of when the call is made.
654 * @param string $method Method call to test.
655 * @param array $args Expected parameters for the call
656 * including wildcards.
657 * @param string $message Overridden message.
658 * @access public
660 function expect($method, $args, $message = '%s') {
661 $this->_dieOnNoMethod($method, 'set expected arguments');
662 $this->_checkArgumentsIsArray($args, 'set expected arguments');
663 $args = $this->_replaceWildcards($args);
664 $message .= Mock::getExpectationLine();
665 $this->_expected_args[strtolower($method)] =
666 new ParametersExpectation($args, $message);
670 * @deprecated
672 function expectArguments($method, $args, $message = '%s') {
673 return $this->expect($method, $args, $message);
677 * Sets up an expected call with a set of
678 * expected parameters in that call. The
679 * expected call count will be adjusted if it
680 * is set too low to reach this call.
681 * @param integer $timing Number of calls in the future at
682 * which to test. Next call is 0.
683 * @param string $method Method call to test.
684 * @param array $args Expected parameters for the call
685 * including wildcards.
686 * @param string $message Overridden message.
687 * @access public
689 function expectAt($timing, $method, $args, $message = '%s') {
690 $this->_dieOnNoMethod($method, 'set expected arguments at time');
691 $this->_checkArgumentsIsArray($args, 'set expected arguments at time');
692 $args = $this->_replaceWildcards($args);
693 if (! isset($this->_expected_args_at[$timing])) {
694 $this->_expected_args_at[$timing] = array();
696 $method = strtolower($method);
697 $message .= Mock::getExpectationLine();
698 $this->_expected_args_at[$timing][$method] =
699 new ParametersExpectation($args, $message);
703 * @deprecated
705 function expectArgumentsAt($timing, $method, $args, $message = '%s') {
706 return $this->expectAt($timing, $method, $args, $message);
710 * Sets an expectation for the number of times
711 * a method will be called. The tally method
712 * is used to check this.
713 * @param string $method Method call to test.
714 * @param integer $count Number of times it should
715 * have been called at tally.
716 * @param string $message Overridden message.
717 * @access public
719 function expectCallCount($method, $count, $message = '%s') {
720 $this->_dieOnNoMethod($method, 'set expected call count');
721 $message .= Mock::getExpectationLine();
722 $this->_expected_counts[strtolower($method)] =
723 new CallCountExpectation($method, $count, $message);
727 * Sets the number of times a method may be called
728 * before a test failure is triggered.
729 * @param string $method Method call to test.
730 * @param integer $count Most number of times it should
731 * have been called.
732 * @param string $message Overridden message.
733 * @access public
735 function expectMaximumCallCount($method, $count, $message = '%s') {
736 $this->_dieOnNoMethod($method, 'set maximum call count');
737 $message .= Mock::getExpectationLine();
738 $this->_max_counts[strtolower($method)] =
739 new MaximumCallCountExpectation($method, $count, $message);
743 * Sets the number of times to call a method to prevent
744 * a failure on the tally.
745 * @param string $method Method call to test.
746 * @param integer $count Least number of times it should
747 * have been called.
748 * @param string $message Overridden message.
749 * @access public
751 function expectMinimumCallCount($method, $count, $message = '%s') {
752 $this->_dieOnNoMethod($method, 'set minimum call count');
753 $message .= Mock::getExpectationLine();
754 $this->_expected_counts[strtolower($method)] =
755 new MinimumCallCountExpectation($method, $count, $message);
759 * Convenience method for barring a method
760 * call.
761 * @param string $method Method call to ban.
762 * @param string $message Overridden message.
763 * @access public
765 function expectNever($method, $message = '%s') {
766 $this->expectMaximumCallCount($method, 0, $message);
770 * Convenience method for a single method
771 * call.
772 * @param string $method Method call to track.
773 * @param array $args Expected argument list or
774 * false for any arguments.
775 * @param string $message Overridden message.
776 * @access public
778 function expectOnce($method, $args = false, $message = '%s') {
779 $this->expectCallCount($method, 1, $message);
780 if ($args !== false) {
781 $this->expectArguments($method, $args, $message);
786 * Convenience method for requiring a method
787 * call.
788 * @param string $method Method call to track.
789 * @param array $args Expected argument list or
790 * false for any arguments.
791 * @param string $message Overridden message.
792 * @access public
794 function expectAtLeastOnce($method, $args = false, $message = '%s') {
795 $this->expectMinimumCallCount($method, 1, $message);
796 if ($args !== false) {
797 $this->expectArguments($method, $args, $message);
802 * @deprecated
804 function tally() {
808 * Receives event from unit test that the current
809 * test method has finished. Totals up the call
810 * counts and triggers a test assertion if a test
811 * is present for expected call counts.
812 * @param string $method Current method name.
813 * @access public
815 function atTestEnd($method) {
816 foreach ($this->_expected_counts as $method => $expectation) {
817 $this->_assertTrue(
818 $expectation->test($this->getCallCount($method)),
819 $expectation->overlayMessage($this->getCallCount($method)));
821 foreach ($this->_max_counts as $method => $expectation) {
822 if ($expectation->test($this->getCallCount($method))) {
823 $this->_assertTrue(
824 true,
825 $expectation->overlayMessage($this->getCallCount($method)));
831 * Returns the expected value for the method name
832 * and checks expectations. Will generate any
833 * test assertions as a result of expectations
834 * if there is a test present.
835 * @param string $method Name of method to simulate.
836 * @param array $args Arguments as an array.
837 * @return mixed Stored return.
838 * @access private
840 function &_invoke($method, $args) {
841 $method = strtolower($method);
842 $step = $this->getCallCount($method);
843 $this->_addCall($method, $args);
844 $this->_checkExpectations($method, $args, $step);
845 $result = &$this->_getReturn($method, $args, $step);
846 return $result;
849 * Finds the return value matching the incoming
850 * arguments. If there is no matching value found
851 * then an error is triggered.
852 * @param string $method Method name.
853 * @param array $args Calling arguments.
854 * @param integer $step Current position in the
855 * call history.
856 * @return mixed Stored return.
857 * @access protected
859 function &_getReturn($method, $args, $step) {
860 if (isset($this->_return_sequence[$method][$step])) {
861 if ($this->_return_sequence[$method][$step]->isMatch($args)) {
862 $result = &$this->_return_sequence[$method][$step]->findFirstMatch($args);
863 return $result;
866 if (isset($this->_returns[$method])) {
867 $result = &$this->_returns[$method]->findFirstMatch($args);
868 return $result;
870 $null = null;
871 return $null;
875 * Tests the arguments against expectations.
876 * @param string $method Method to check.
877 * @param array $args Argument list to match.
878 * @param integer $timing The position of this call
879 * in the call history.
880 * @access private
882 function _checkExpectations($method, $args, $timing) {
883 if (isset($this->_max_counts[$method])) {
884 if (! $this->_max_counts[$method]->test($timing + 1)) {
885 $this->_assertTrue(
886 false,
887 $this->_max_counts[$method]->overlayMessage($timing + 1));
890 if (isset($this->_expected_args_at[$timing][$method])) {
891 $this->_assertTrue(
892 $this->_expected_args_at[$timing][$method]->test($args),
893 "Mock method [$method] at [$timing] -> " .
894 $this->_expected_args_at[$timing][$method]->overlayMessage($args));
895 } elseif (isset($this->_expected_args[$method])) {
896 $this->_assertTrue(
897 $this->_expected_args[$method]->test($args),
898 "Mock method [$method] -> " . $this->_expected_args[$method]->overlayMessage($args));
903 * Triggers an assertion on the held test case.
904 * Should be overridden when using another test
905 * framework other than the SimpleTest one if the
906 * assertion method has a different name.
907 * @param boolean $assertion True will pass.
908 * @param string $message Message that will go with
909 * the test event.
910 * @access protected
912 function _assertTrue($assertion, $message) {
913 $test = &$this->_getCurrentTestCase();
914 $test->assertTrue($assertion, $message);
919 * Static methods only service class for code generation of
920 * mock objects.
921 * @package SimpleTest
922 * @subpackage MockObjects
924 class Mock {
927 * Factory for mock object classes.
928 * @access public
930 function Mock() {
931 //trigger_error('Mock factory methods are class only.');
935 * Clones a class' interface and creates a mock version
936 * that can have return values and expectations set.
937 * @param string $class Class to clone.
938 * @param string $mock_class New class name. Default is
939 * the old name with "Mock"
940 * prepended.
941 * @param array $methods Additional methods to add beyond
942 * those in th cloned class. Use this
943 * to emulate the dynamic addition of
944 * methods in the cloned class or when
945 * the class hasn't been written yet.
946 * @static
947 * @access public
949 function generate($class, $mock_class = false, $methods = false) {
950 $generator = new MockGenerator($class, $mock_class);
951 return $generator->generate($methods);
955 * Generates a version of a class with selected
956 * methods mocked only. Inherits the old class
957 * and chains the mock methods of an aggregated
958 * mock object.
959 * @param string $class Class to clone.
960 * @param string $mock_class New class name.
961 * @param array $methods Methods to be overridden
962 * with mock versions.
963 * @static
964 * @access public
966 function generatePartial($class, $mock_class, $methods) {
967 $generator = new MockGenerator($class, $mock_class);
968 return $generator->generatePartial($methods);
972 * Uses a stack trace to find the line of an assertion.
973 * @param array $stack Stack frames top most first. Only
974 * needed if not using the PHP
975 * backtrace function.
976 * @return string Location of first expect*
977 * method embedded in format string.
978 * @access public
979 * @static
981 function getExpectationLine($stack = false) {
982 if ($stack === false) {
983 $stack = SimpleTestCompatibility::getStackTrace();
985 return SimpleDumper::getFormattedAssertionLine($stack);
990 * @deprecated
992 class Stub extends Mock {
996 * Service class for code generation of mock objects.
997 * @package SimpleTest
998 * @subpackage MockObjects
1000 class MockGenerator {
1001 var $_class;
1002 var $_mock_class;
1003 var $_mock_base;
1004 var $_reflection;
1006 function MockGenerator($class, $mock_class) {
1007 $this->_class = $class;
1008 $this->_mock_class = $mock_class;
1009 $this->_mock_base = SimpleTest::getMockBaseClass();
1010 $this->_reflection = new SimpleReflection($this->_class);
1014 * Clones a class' interface and creates a mock version
1015 * that can have return values and expectations set.
1016 * @param array $methods Additional methods to add beyond
1017 * those in th cloned class. Use this
1018 * to emulate the dynamic addition of
1019 * methods in the cloned class or when
1020 * the class hasn't been written yet.
1021 * @access public
1023 function generate($methods) {
1024 if (! $this->_reflection->classOrInterfaceExists()) {
1025 return false;
1027 if (! $this->_mock_class) {
1028 $this->_mock_class = 'Mock' . $this->_class;
1030 $mock_reflection = new SimpleReflection($this->_mock_class);
1031 if ($mock_reflection->classExistsSansAutoload()) {
1032 return false;
1034 return eval(
1035 $this->_createClassCode($methods ? $methods : array()) .
1036 " return true;");
1040 * Generates a version of a class with selected
1041 * methods mocked only. Inherits the old class
1042 * and chains the mock methods of an aggregated
1043 * mock object.
1044 * @param array $methods Methods to be overridden
1045 * with mock versions.
1046 * @access public
1048 function generatePartial($methods) {
1049 if (! $this->_reflection->classExists($this->_class)) {
1050 return false;
1052 $mock_reflection = new SimpleReflection($this->_mock_class);
1053 if ($mock_reflection->classExistsSansAutoload()) {
1054 trigger_error("Partial mock class [$mock_class] already exists");
1055 return false;
1057 return eval($this->_extendClassCode($methods));
1061 * The new mock class code as a string.
1062 * @param array $methods Additional methods.
1063 * @return string Code for new mock class.
1064 * @access private
1066 function _createClassCode($methods) {
1067 $implements = '';
1068 $interfaces = $this->_reflection->getInterfaces();
1069 if (function_exists('spl_classes')) {
1070 $interfaces = array_diff($interfaces, array('Traversable'));
1072 if (count($interfaces) > 0) {
1073 $implements = 'implements ' . implode(', ', $interfaces);
1075 $code = "class " . $this->_mock_class . " extends " . $this->_mock_base . " $implements {\n";
1076 $code .= " function " . $this->_mock_class . "() {\n";
1077 $code .= " \$this->" . $this->_mock_base . "();\n";
1078 $code .= " }\n";
1079 $code .= $this->_createHandlerCode($methods);
1080 $code .= "}\n";
1081 return $code;
1085 * The extension class code as a string. The class
1086 * composites a mock object and chains mocked methods
1087 * to it.
1088 * @param array $methods Mocked methods.
1089 * @return string Code for a new class.
1090 * @access private
1092 function _extendClassCode($methods) {
1093 $code = "class " . $this->_mock_class . " extends " . $this->_class . " {\n";
1094 $code .= " var \$_mock;\n";
1095 $code .= $this->_addMethodList($methods);
1096 $code .= "\n";
1097 $code .= " function " . $this->_mock_class . "() {\n";
1098 $code .= " \$this->_mock = &new " . $this->_mock_base . "();\n";
1099 $code .= " \$this->_mock->disableExpectationNameChecks();\n";
1100 $code .= " }\n";
1101 $code .= $this->_chainMockReturns();
1102 $code .= $this->_chainMockExpectations();
1103 $code .= $this->_overrideMethods($methods);
1104 $code .= "}\n";
1105 return $code;
1109 * Creates code within a class to generate replaced
1110 * methods. All methods call the _invoke() handler
1111 * with the method name and the arguments in an
1112 * array.
1113 * @param array $methods Additional methods.
1114 * @access private
1116 function _createHandlerCode($methods) {
1117 $code = '';
1118 $methods = array_merge($methods, $this->_reflection->getMethods());
1119 foreach ($methods as $method) {
1120 if ($this->_isConstructor($method)) {
1121 continue;
1123 $mock_reflection = new SimpleReflection($this->_mock_base);
1124 if (in_array($method, $mock_reflection->getMethods())) {
1125 continue;
1127 $code .= " " . $this->_reflection->getSignature($method) . " {\n";
1128 $code .= " \$args = func_get_args();\n";
1129 $code .= " \$result = &\$this->_invoke(\"$method\", \$args);\n";
1130 $code .= " return \$result;\n";
1131 $code .= " }\n";
1133 return $code;
1137 * Tests to see if a special PHP method is about to
1138 * be stubbed by mistake.
1139 * @param string $method Method name.
1140 * @return boolean True if special.
1141 * @access private
1143 function _isConstructor($method) {
1144 return in_array(
1145 strtolower($method),
1146 array('__construct', '__destruct', '__clone'));
1150 * Creates a list of mocked methods for error checking.
1151 * @param array $methods Mocked methods.
1152 * @return string Code for a method list.
1153 * @access private
1155 function _addMethodList($methods) {
1156 return " var \$_mocked_methods = array('" . implode("', '", $methods) . "');\n";
1160 * Creates code to abandon the expectation if not mocked.
1161 * @param string $alias Parameter name of method name.
1162 * @return string Code for bail out.
1163 * @access private
1165 function _bailOutIfNotMocked($alias) {
1166 $code = " if (! in_array($alias, \$this->_mocked_methods)) {\n";
1167 $code .= " trigger_error(\"Method [$alias] is not mocked\");\n";
1168 $code .= " \$null = null;\n";
1169 $code .= " return \$null;\n";
1170 $code .= " }\n";
1171 return $code;
1175 * Creates source code for chaining to the composited
1176 * mock object.
1177 * @return string Code for mock set up.
1178 * @access private
1180 function _chainMockReturns() {
1181 $code = " function setReturnValue(\$method, \$value, \$args = false) {\n";
1182 $code .= $this->_bailOutIfNotMocked("\$method");
1183 $code .= " \$this->_mock->setReturnValue(\$method, \$value, \$args);\n";
1184 $code .= " }\n";
1185 $code .= " function setReturnValueAt(\$timing, \$method, \$value, \$args = false) {\n";
1186 $code .= $this->_bailOutIfNotMocked("\$method");
1187 $code .= " \$this->_mock->setReturnValueAt(\$timing, \$method, \$value, \$args);\n";
1188 $code .= " }\n";
1189 $code .= " function setReturnReference(\$method, &\$ref, \$args = false) {\n";
1190 $code .= $this->_bailOutIfNotMocked("\$method");
1191 $code .= " \$this->_mock->setReturnReference(\$method, \$ref, \$args);\n";
1192 $code .= " }\n";
1193 $code .= " function setReturnReferenceAt(\$timing, \$method, &\$ref, \$args = false) {\n";
1194 $code .= $this->_bailOutIfNotMocked("\$method");
1195 $code .= " \$this->_mock->setReturnReferenceAt(\$timing, \$method, \$ref, \$args);\n";
1196 $code .= " }\n";
1197 return $code;
1201 * Creates source code for chaining to an aggregated
1202 * mock object.
1203 * @return string Code for expectations.
1204 * @access private
1206 function _chainMockExpectations() {
1207 $code = " function expect(\$method, \$args = false) {\n";
1208 $code .= $this->_bailOutIfNotMocked("\$method");
1209 $code .= " \$this->_mock->expect(\$method, \$args);\n";
1210 $code .= " }\n";
1211 $code .= " function expectArguments(\$method, \$args = false) {\n";
1212 $code .= $this->_bailOutIfNotMocked("\$method");
1213 $code .= " \$this->_mock->expectArguments(\$method, \$args);\n";
1214 $code .= " }\n";
1215 $code .= " function expectAt(\$timing, \$method, \$args = false) {\n";
1216 $code .= $this->_bailOutIfNotMocked("\$method");
1217 $code .= " \$this->_mock->expectArgumentsAt(\$timing, \$method, \$args);\n";
1218 $code .= " }\n";
1219 $code .= " function expectArgumentsAt(\$timing, \$method, \$args = false) {\n";
1220 $code .= $this->_bailOutIfNotMocked("\$method");
1221 $code .= " \$this->_mock->expectArgumentsAt(\$timing, \$method, \$args);\n";
1222 $code .= " }\n";
1223 $code .= " function expectCallCount(\$method, \$count) {\n";
1224 $code .= $this->_bailOutIfNotMocked("\$method");
1225 $code .= " \$this->_mock->expectCallCount(\$method, \$count);\n";
1226 $code .= " }\n";
1227 $code .= " function expectMaximumCallCount(\$method, \$count) {\n";
1228 $code .= $this->_bailOutIfNotMocked("\$method");
1229 $code .= " \$this->_mock->expectMaximumCallCount(\$method, \$count);\n";
1230 $code .= " }\n";
1231 $code .= " function expectMinimumCallCount(\$method, \$count) {\n";
1232 $code .= $this->_bailOutIfNotMocked("\$method");
1233 $code .= " \$this->_mock->expectMinimumCallCount(\$method, \$count);\n";
1234 $code .= " }\n";
1235 $code .= " function expectNever(\$method) {\n";
1236 $code .= $this->_bailOutIfNotMocked("\$method");
1237 $code .= " \$this->_mock->expectNever(\$method);\n";
1238 $code .= " }\n";
1239 $code .= " function expectOnce(\$method, \$args = false) {\n";
1240 $code .= $this->_bailOutIfNotMocked("\$method");
1241 $code .= " \$this->_mock->expectOnce(\$method, \$args);\n";
1242 $code .= " }\n";
1243 $code .= " function expectAtLeastOnce(\$method, \$args = false) {\n";
1244 $code .= $this->_bailOutIfNotMocked("\$method");
1245 $code .= " \$this->_mock->expectAtLeastOnce(\$method, \$args);\n";
1246 $code .= " }\n";
1247 $code .= " function tally() {\n";
1248 $code .= " \$this->_mock->tally();\n";
1249 $code .= " }\n";
1250 return $code;
1254 * Creates source code to override a list of methods
1255 * with mock versions.
1256 * @param array $methods Methods to be overridden
1257 * with mock versions.
1258 * @return string Code for overridden chains.
1259 * @access private
1261 function _overrideMethods($methods) {
1262 $code = "";
1263 foreach ($methods as $method) {
1264 $code .= " " . $this->_reflection->getSignature($method) . " {\n";
1265 $code .= " \$args = func_get_args();\n";
1266 $code .= " \$result = &\$this->_mock->_invoke(\"$method\", \$args);\n";
1267 $code .= " return \$result;\n";
1268 $code .= " }\n";
1270 return $code;