PageRenderTime 55ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/application/libraries/simpletest/mock_objects.php

https://bitbucket.org/mercucci/mercucci
PHP | 1581 lines | 754 code | 104 blank | 723 comment | 67 complexity | 3470e36f5e1e52eaebae4617f675b046 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * base include file for SimpleTest
  4. * @package SimpleTest
  5. * @subpackage MockObjects
  6. * @version $Id: mock_objects.php 1672 2008-03-02 04:47:34Z edwardzyang $
  7. */
  8. /**#@+
  9. * include SimpleTest files
  10. */
  11. require_once(dirname(__FILE__) . '/expectation.php');
  12. require_once(dirname(__FILE__) . '/simpletest.php');
  13. require_once(dirname(__FILE__) . '/dumper.php');
  14. if (version_compare(phpversion(), '5') >= 0) {
  15. require_once(dirname(__FILE__) . '/reflection_php5.php');
  16. } else {
  17. require_once(dirname(__FILE__) . '/reflection_php4.php');
  18. }
  19. /**#@-*/
  20. /**
  21. * Default character simpletest will substitute for any value
  22. */
  23. if (! defined('MOCK_ANYTHING')) {
  24. define('MOCK_ANYTHING', '*');
  25. }
  26. /**
  27. * Parameter comparison assertion.
  28. * @package SimpleTest
  29. * @subpackage MockObjects
  30. */
  31. class ParametersExpectation extends SimpleExpectation {
  32. var $_expected;
  33. /**
  34. * Sets the expected parameter list.
  35. * @param array $parameters Array of parameters including
  36. * those that are wildcarded.
  37. * If the value is not an array
  38. * then it is considered to match any.
  39. * @param string $message Customised message on failure.
  40. * @access public
  41. */
  42. function ParametersExpectation($expected = false, $message = '%s') {
  43. $this->SimpleExpectation($message);
  44. $this->_expected = $expected;
  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. * Tests an individual parameter.
  68. * @param mixed $parameter Value to test.
  69. * @param mixed $expected Comparison value.
  70. * @return boolean True if expectation
  71. * fulfilled.
  72. * @access private
  73. */
  74. function _testParameter($parameter, $expected) {
  75. $comparison = $this->_coerceToExpectation($expected);
  76. return $comparison->test($parameter);
  77. }
  78. /**
  79. * Returns a human readable test message.
  80. * @param array $comparison Incoming parameter list.
  81. * @return string Description of success
  82. * or failure.
  83. * @access public
  84. */
  85. function testMessage($parameters) {
  86. if ($this->test($parameters)) {
  87. return "Expectation of " . count($this->_expected) .
  88. " arguments of [" . $this->_renderArguments($this->_expected) .
  89. "] is correct";
  90. } else {
  91. return $this->_describeDifference($this->_expected, $parameters);
  92. }
  93. }
  94. /**
  95. * Message to display if expectation differs from
  96. * the parameters actually received.
  97. * @param array $expected Expected parameters as list.
  98. * @param array $parameters Actual parameters received.
  99. * @return string Description of difference.
  100. * @access private
  101. */
  102. function _describeDifference($expected, $parameters) {
  103. if (count($expected) != count($parameters)) {
  104. return "Expected " . count($expected) .
  105. " arguments of [" . $this->_renderArguments($expected) .
  106. "] but got " . count($parameters) .
  107. " arguments of [" . $this->_renderArguments($parameters) . "]";
  108. }
  109. $messages = array();
  110. for ($i = 0; $i < count($expected); $i++) {
  111. $comparison = $this->_coerceToExpectation($expected[$i]);
  112. if (! $comparison->test($parameters[$i])) {
  113. $messages[] = "parameter " . ($i + 1) . " with [" .
  114. $comparison->overlayMessage($parameters[$i], $this->_getDumper()) . "]";
  115. }
  116. }
  117. return "Parameter expectation differs at " . implode(" and ", $messages);
  118. }
  119. /**
  120. * Creates an identical expectation if the
  121. * object/value is not already some type
  122. * of expectation.
  123. * @param mixed $expected Expected value.
  124. * @return SimpleExpectation Expectation object.
  125. * @access private
  126. */
  127. function _coerceToExpectation($expected) {
  128. if (SimpleExpectation::isExpectation($expected)) {
  129. return $expected;
  130. }
  131. return new IdenticalExpectation($expected);
  132. }
  133. /**
  134. * Renders the argument list as a string for
  135. * messages.
  136. * @param array $args Incoming arguments.
  137. * @return string Simple description of type and value.
  138. * @access private
  139. */
  140. function _renderArguments($args) {
  141. $descriptions = array();
  142. if (is_array($args)) {
  143. foreach ($args as $arg) {
  144. $dumper = &new SimpleDumper();
  145. $descriptions[] = $dumper->describeValue($arg);
  146. }
  147. }
  148. return implode(', ', $descriptions);
  149. }
  150. }
  151. /**
  152. * Confirms that the number of calls on a method is as expected.
  153. * @package SimpleTest
  154. * @subpackage MockObjects
  155. */
  156. class CallCountExpectation extends SimpleExpectation {
  157. var $_method;
  158. var $_count;
  159. /**
  160. * Stashes the method and expected count for later
  161. * reporting.
  162. * @param string $method Name of method to confirm against.
  163. * @param integer $count Expected number of calls.
  164. * @param string $message Custom error message.
  165. */
  166. function CallCountExpectation($method, $count, $message = '%s') {
  167. $this->_method = $method;
  168. $this->_count = $count;
  169. $this->SimpleExpectation($message);
  170. }
  171. /**
  172. * Tests the assertion. True if correct.
  173. * @param integer $compare Measured call count.
  174. * @return boolean True if expected.
  175. * @access public
  176. */
  177. function test($compare) {
  178. return ($this->_count == $compare);
  179. }
  180. /**
  181. * Reports the comparison.
  182. * @param integer $compare Measured call count.
  183. * @return string Message to show.
  184. * @access public
  185. */
  186. function testMessage($compare) {
  187. return 'Expected call count for [' . $this->_method .
  188. '] was [' . $this->_count .
  189. '] got [' . $compare . ']';
  190. }
  191. }
  192. /**
  193. * Confirms that the number of calls on a method is as expected.
  194. * @package SimpleTest
  195. * @subpackage MockObjects
  196. */
  197. class MinimumCallCountExpectation extends SimpleExpectation {
  198. var $_method;
  199. var $_count;
  200. /**
  201. * Stashes the method and expected count for later
  202. * reporting.
  203. * @param string $method Name of method to confirm against.
  204. * @param integer $count Minimum number of calls.
  205. * @param string $message Custom error message.
  206. */
  207. function MinimumCallCountExpectation($method, $count, $message = '%s') {
  208. $this->_method = $method;
  209. $this->_count = $count;
  210. $this->SimpleExpectation($message);
  211. }
  212. /**
  213. * Tests the assertion. True if correct.
  214. * @param integer $compare Measured call count.
  215. * @return boolean True if enough.
  216. * @access public
  217. */
  218. function test($compare) {
  219. return ($this->_count <= $compare);
  220. }
  221. /**
  222. * Reports the comparison.
  223. * @param integer $compare Measured call count.
  224. * @return string Message to show.
  225. * @access public
  226. */
  227. function testMessage($compare) {
  228. return 'Minimum call count for [' . $this->_method .
  229. '] was [' . $this->_count .
  230. '] got [' . $compare . ']';
  231. }
  232. }
  233. /**
  234. * Confirms that the number of calls on a method is as expected.
  235. * @package SimpleTest
  236. * @subpackage MockObjects
  237. */
  238. class MaximumCallCountExpectation extends SimpleExpectation {
  239. var $_method;
  240. var $_count;
  241. /**
  242. * Stashes the method and expected count for later
  243. * reporting.
  244. * @param string $method Name of method to confirm against.
  245. * @param integer $count Minimum number of calls.
  246. * @param string $message Custom error message.
  247. */
  248. function MaximumCallCountExpectation($method, $count, $message = '%s') {
  249. $this->_method = $method;
  250. $this->_count = $count;
  251. $this->SimpleExpectation($message);
  252. }
  253. /**
  254. * Tests the assertion. True if correct.
  255. * @param integer $compare Measured call count.
  256. * @return boolean True if not over.
  257. * @access public
  258. */
  259. function test($compare) {
  260. return ($this->_count >= $compare);
  261. }
  262. /**
  263. * Reports the comparison.
  264. * @param integer $compare Measured call count.
  265. * @return string Message to show.
  266. * @access public
  267. */
  268. function testMessage($compare) {
  269. return 'Maximum call count for [' . $this->_method .
  270. '] was [' . $this->_count .
  271. '] got [' . $compare . ']';
  272. }
  273. }
  274. /**
  275. * Retrieves method actions by searching the
  276. * parameter lists until an expected match is found.
  277. * @package SimpleTest
  278. * @subpackage MockObjects
  279. */
  280. class SimpleSignatureMap {
  281. var $_map;
  282. /**
  283. * Creates an empty call map.
  284. * @access public
  285. */
  286. function SimpleSignatureMap() {
  287. $this->_map = array();
  288. }
  289. /**
  290. * Stashes a reference against a method call.
  291. * @param array $parameters Array of arguments (including wildcards).
  292. * @param mixed $action Reference placed in the map.
  293. * @access public
  294. */
  295. function add($parameters, &$action) {
  296. $place = count($this->_map);
  297. $this->_map[$place] = array();
  298. $this->_map[$place]['params'] = new ParametersExpectation($parameters);
  299. $this->_map[$place]['content'] = &$action;
  300. }
  301. /**
  302. * Searches the call list for a matching parameter
  303. * set. Returned by reference.
  304. * @param array $parameters Parameters to search by
  305. * without wildcards.
  306. * @return object Object held in the first matching
  307. * slot, otherwise null.
  308. * @access public
  309. */
  310. function &findFirstAction($parameters) {
  311. $slot = $this->_findFirstSlot($parameters);
  312. if (isset($slot) && isset($slot['content'])) {
  313. return $slot['content'];
  314. }
  315. $null = null;
  316. return $null;
  317. }
  318. /**
  319. * Searches the call list for a matching parameter
  320. * set. True if successful.
  321. * @param array $parameters Parameters to search by
  322. * without wildcards.
  323. * @return boolean True if a match is present.
  324. * @access public
  325. */
  326. function isMatch($parameters) {
  327. return ($this->_findFirstSlot($parameters) != null);
  328. }
  329. /**
  330. * Compares the incoming parameters with the
  331. * internal expectation. Uses the incoming $test
  332. * to dispatch the test message.
  333. * @param SimpleTestCase $test Test to dispatch to.
  334. * @param array $parameters The actual calling arguments.
  335. * @param string $message The message to overlay.
  336. * @access public
  337. */
  338. function test(&$test, $parameters, $message) {
  339. }
  340. /**
  341. * Searches the map for a matching item.
  342. * @param array $parameters Parameters to search by
  343. * without wildcards.
  344. * @return array Reference to slot or null.
  345. * @access private
  346. */
  347. function &_findFirstSlot($parameters) {
  348. $count = count($this->_map);
  349. for ($i = 0; $i < $count; $i++) {
  350. if ($this->_map[$i]["params"]->test($parameters)) {
  351. return $this->_map[$i];
  352. }
  353. }
  354. $null = null;
  355. return $null;
  356. }
  357. }
  358. /**
  359. * Allows setting of actions against call signatures either
  360. * at a specific time, or always. Specific time settings
  361. * trump lasting ones, otherwise the most recently added
  362. * will mask an earlier match.
  363. * @package SimpleTest
  364. * @subpackage MockObjects
  365. */
  366. class SimpleCallSchedule {
  367. var $_wildcard = MOCK_ANYTHING;
  368. var $_always;
  369. var $_at;
  370. /**
  371. * Sets up an empty response schedule.
  372. * Creates an empty call map.
  373. */
  374. function SimpleCallSchedule() {
  375. $this->_always = array();
  376. $this->_at = array();
  377. }
  378. /**
  379. * Stores an action against a signature that
  380. * will always fire unless masked by a time
  381. * specific one.
  382. * @param string $method Method name.
  383. * @param array $args Calling parameters.
  384. * @param SimpleAction $action Actually simpleByValue, etc.
  385. * @access public
  386. */
  387. function register($method, $args, &$action) {
  388. $args = $this->_replaceWildcards($args);
  389. $method = strtolower($method);
  390. if (! isset($this->_always[$method])) {
  391. $this->_always[$method] = new SimpleSignatureMap();
  392. }
  393. $this->_always[$method]->add($args, $action);
  394. }
  395. /**
  396. * Stores an action against a signature that
  397. * will fire at a specific time in the future.
  398. * @param integer $step delay of calls to this method,
  399. * 0 is next.
  400. * @param string $method Method name.
  401. * @param array $args Calling parameters.
  402. * @param SimpleAction $action Actually SimpleByValue, etc.
  403. * @access public
  404. */
  405. function registerAt($step, $method, $args, &$action) {
  406. $args = $this->_replaceWildcards($args);
  407. $method = strtolower($method);
  408. if (! isset($this->_at[$method])) {
  409. $this->_at[$method] = array();
  410. }
  411. if (! isset($this->_at[$method][$step])) {
  412. $this->_at[$method][$step] = new SimpleSignatureMap();
  413. }
  414. $this->_at[$method][$step]->add($args, $action);
  415. }
  416. function expectArguments($method, $args, $message) {
  417. $args = $this->_replaceWildcards($args);
  418. $message .= Mock::getExpectationLine();
  419. $this->_expected_args[strtolower($method)] =
  420. new ParametersExpectation($args, $message);
  421. }
  422. /**
  423. * Actually carry out the action stored previously,
  424. * if the parameters match.
  425. * @param integer $step Time of call.
  426. * @param string $method Method name.
  427. * @param array $args The parameters making up the
  428. * rest of the call.
  429. * @return mixed The result of the action.
  430. * @access public.
  431. */
  432. function &respond($step, $method, $args) {
  433. $method = strtolower($method);
  434. if (isset($this->_at[$method][$step])) {
  435. if ($this->_at[$method][$step]->isMatch($args)) {
  436. $action = &$this->_at[$method][$step]->findFirstAction($args);
  437. if (isset($action)) {
  438. return $action->act();
  439. }
  440. }
  441. }
  442. if (isset($this->_always[$method])) {
  443. $action = &$this->_always[$method]->findFirstAction($args);
  444. if (isset($action)) {
  445. return $action->act();
  446. }
  447. }
  448. $null = null;
  449. return $null;
  450. }
  451. /**
  452. * Replaces wildcard matches with wildcard
  453. * expectations in the argument list.
  454. * @param array $args Raw argument list.
  455. * @return array Argument list with
  456. * expectations.
  457. * @access private
  458. */
  459. function _replaceWildcards($args) {
  460. if ($args === false) {
  461. return false;
  462. }
  463. for ($i = 0; $i < count($args); $i++) {
  464. if ($args[$i] === $this->_wildcard) {
  465. $args[$i] = new AnythingExpectation();
  466. }
  467. }
  468. return $args;
  469. }
  470. }
  471. /**
  472. * A type of SimpleMethodAction.
  473. * Stashes a reference for returning later.
  474. * @package SimpleTest
  475. * @subpackage MockObjects
  476. */
  477. class SimpleByReference {
  478. var $_reference;
  479. /**
  480. * Stashes it for later.
  481. * @param mixed $reference Actual PHP4 style reference.
  482. * @access public
  483. */
  484. function SimpleByReference(&$reference) {
  485. $this->_reference = &$reference;
  486. }
  487. /**
  488. * Returns the reference stored earlier.
  489. * @return mixed Whatever was stashed.
  490. * @access public
  491. */
  492. function &act() {
  493. return $this->_reference;
  494. }
  495. }
  496. /**
  497. * A type of SimpleMethodAction.
  498. * Stashes a value for returning later.
  499. * @package SimpleTest
  500. * @subpackage MockObjects
  501. */
  502. class SimpleByValue {
  503. var $_value;
  504. /**
  505. * Stashes it for later.
  506. * @param mixed $value You need to clone objects
  507. * if you want copy semantics
  508. * for these.
  509. * @access public
  510. */
  511. function SimpleByValue($value) {
  512. $this->_value = $value;
  513. }
  514. /**
  515. * Returns the value stored earlier.
  516. * @return mixed Whatever was stashed.
  517. * @access public
  518. */
  519. function &act() {
  520. $dummy = $this->_value;
  521. return $dummy;
  522. }
  523. }
  524. /**
  525. * A type of SimpleMethodAction.
  526. * Stashes an exception for throwing later.
  527. * @package SimpleTest
  528. * @subpackage MockObjects
  529. */
  530. class SimpleThrower {
  531. var $_exception;
  532. /**
  533. * Stashes it for later.
  534. * @param Exception $exception The exception object to throw.
  535. * @access public
  536. */
  537. function SimpleThrower($exception) {
  538. $this->_exception = $exception;
  539. }
  540. /**
  541. * Throws the exceptins stashed earlier.
  542. * @access public
  543. */
  544. function act() {
  545. eval('throw $this->_exception;');
  546. }
  547. }
  548. /**
  549. * A type of SimpleMethodAction.
  550. * Stashes an error for emitting later.
  551. * @package SimpleTest
  552. * @subpackage MockObjects
  553. */
  554. class SimpleErrorThrower {
  555. var $_error;
  556. var $_severity;
  557. /**
  558. * Stashes an error to throw later.
  559. * @param string $error Error message.
  560. * @param integer $severity PHP error constant, e.g E_USER_ERROR.
  561. * @access public
  562. */
  563. function SimpleErrorThrower($error, $severity) {
  564. $this->_error = $error;
  565. $this->_severity = $severity;
  566. }
  567. /**
  568. * Triggers the stashed error.
  569. * @return null The usual PHP4.4 shenanigans are needed here.
  570. * @access public
  571. */
  572. function &act() {
  573. trigger_error($this->_error, $this->_severity);
  574. $null = null;
  575. return $null;
  576. }
  577. }
  578. /**
  579. * A base class or delegate that extends an
  580. * empty collection of methods that can have their
  581. * return values set and expectations made of the
  582. * calls upon them. The mock will assert the
  583. * expectations against it's attached test case in
  584. * addition to the server stub behaviour or returning
  585. * preprogrammed responses.
  586. * @package SimpleTest
  587. * @subpackage MockObjects
  588. */
  589. class SimpleMock {
  590. var $_actions;
  591. var $_wildcard = MOCK_ANYTHING;
  592. var $_is_strict = true;
  593. var $_call_counts;
  594. var $_expected_counts;
  595. var $_max_counts;
  596. var $_expected_args;
  597. var $_expected_args_at;
  598. /**
  599. * Creates an empty action list and expectation list.
  600. * All call counts are set to zero.
  601. * @access public
  602. */
  603. function SimpleMock() {
  604. $this->_actions = &new SimpleCallSchedule();
  605. $this->_expectations = &new SimpleCallSchedule();
  606. $this->_call_counts = array();
  607. $this->_expected_counts = array();
  608. $this->_max_counts = array();
  609. $this->_expected_args = array();
  610. $this->_expected_args_at = array();
  611. $test = &$this->_getCurrentTestCase();
  612. $test->tell($this);
  613. }
  614. /**
  615. * Disables a name check when setting expectations.
  616. * This hack is needed for the partial mocks.
  617. * @access public
  618. */
  619. function disableExpectationNameChecks() {
  620. $this->_is_strict = false;
  621. }
  622. /**
  623. * Finds currently running test.
  624. * @return SimpeTestCase Current test case.
  625. * @access protected
  626. */
  627. function &_getCurrentTestCase() {
  628. $context = &SimpleTest::getContext();
  629. return $context->getTest();
  630. }
  631. /**
  632. * Die if bad arguments array is passed.
  633. * @param mixed $args The arguments value to be checked.
  634. * @param string $task Description of task attempt.
  635. * @return boolean Valid arguments
  636. * @access private
  637. */
  638. function _checkArgumentsIsArray($args, $task) {
  639. if (! is_array($args)) {
  640. trigger_error(
  641. "Cannot $task as \$args parameter is not an array",
  642. E_USER_ERROR);
  643. }
  644. }
  645. /**
  646. * Triggers a PHP error if the method is not part
  647. * of this object.
  648. * @param string $method Name of method.
  649. * @param string $task Description of task attempt.
  650. * @access protected
  651. */
  652. function _dieOnNoMethod($method, $task) {
  653. if ($this->_is_strict && ! method_exists($this, $method)) {
  654. trigger_error(
  655. "Cannot $task as no ${method}() in class " . get_class($this),
  656. E_USER_ERROR);
  657. }
  658. }
  659. /**
  660. * Replaces wildcard matches with wildcard
  661. * expectations in the argument list.
  662. * @param array $args Raw argument list.
  663. * @return array Argument list with
  664. * expectations.
  665. * @access private
  666. */
  667. function _replaceWildcards($args) {
  668. if ($args === false) {
  669. return false;
  670. }
  671. for ($i = 0; $i < count($args); $i++) {
  672. if ($args[$i] === $this->_wildcard) {
  673. $args[$i] = new AnythingExpectation();
  674. }
  675. }
  676. return $args;
  677. }
  678. /**
  679. * Adds one to the call count of a method.
  680. * @param string $method Method called.
  681. * @param array $args Arguments as an array.
  682. * @access protected
  683. */
  684. function _addCall($method, $args) {
  685. if (! isset($this->_call_counts[$method])) {
  686. $this->_call_counts[$method] = 0;
  687. }
  688. $this->_call_counts[$method]++;
  689. }
  690. /**
  691. * Fetches the call count of a method so far.
  692. * @param string $method Method name called.
  693. * @return integer Number of calls so far.
  694. * @access public
  695. */
  696. function getCallCount($method) {
  697. $this->_dieOnNoMethod($method, "get call count");
  698. $method = strtolower($method);
  699. if (! isset($this->_call_counts[$method])) {
  700. return 0;
  701. }
  702. return $this->_call_counts[$method];
  703. }
  704. /**
  705. * Sets a return for a parameter list that will
  706. * be passed by value for all calls to this method.
  707. * @param string $method Method name.
  708. * @param mixed $value Result of call passed by value.
  709. * @param array $args List of parameters to match
  710. * including wildcards.
  711. * @access public
  712. */
  713. function setReturnValue($method, $value, $args = false) {
  714. $this->_dieOnNoMethod($method, "set return value");
  715. $this->_actions->register($method, $args, new SimpleByValue($value));
  716. }
  717. /**
  718. * Sets a return for a parameter list that will
  719. * be passed by value only when the required call count
  720. * is reached.
  721. * @param integer $timing Number of calls in the future
  722. * to which the result applies. If
  723. * not set then all calls will return
  724. * the value.
  725. * @param string $method Method name.
  726. * @param mixed $value Result of call passed by value.
  727. * @param array $args List of parameters to match
  728. * including wildcards.
  729. * @access public
  730. */
  731. function setReturnValueAt($timing, $method, $value, $args = false) {
  732. $this->_dieOnNoMethod($method, "set return value sequence");
  733. $this->_actions->registerAt($timing, $method, $args, new SimpleByValue($value));
  734. }
  735. /**
  736. * Sets a return for a parameter list that will
  737. * be passed by reference for all calls.
  738. * @param string $method Method name.
  739. * @param mixed $reference Result of the call will be this object.
  740. * @param array $args List of parameters to match
  741. * including wildcards.
  742. * @access public
  743. */
  744. function setReturnReference($method, &$reference, $args = false) {
  745. $this->_dieOnNoMethod($method, "set return reference");
  746. $this->_actions->register($method, $args, new SimpleByReference($reference));
  747. }
  748. /**
  749. * Sets a return for a parameter list that will
  750. * be passed by value only when the required call count
  751. * is reached.
  752. * @param integer $timing Number of calls in the future
  753. * to which the result applies. If
  754. * not set then all calls will return
  755. * the value.
  756. * @param string $method Method name.
  757. * @param mixed $reference Result of the call will be this object.
  758. * @param array $args List of parameters to match
  759. * including wildcards.
  760. * @access public
  761. */
  762. function setReturnReferenceAt($timing, $method, &$reference, $args = false) {
  763. $this->_dieOnNoMethod($method, "set return reference sequence");
  764. $this->_actions->registerAt($timing, $method, $args, new SimpleByReference($reference));
  765. }
  766. /**
  767. * Sets up an expected call with a set of
  768. * expected parameters in that call. All
  769. * calls will be compared to these expectations
  770. * regardless of when the call is made.
  771. * @param string $method Method call to test.
  772. * @param array $args Expected parameters for the call
  773. * including wildcards.
  774. * @param string $message Overridden message.
  775. * @access public
  776. */
  777. function expect($method, $args, $message = '%s') {
  778. $this->_dieOnNoMethod($method, 'set expected arguments');
  779. $this->_checkArgumentsIsArray($args, 'set expected arguments');
  780. $this->_expectations->expectArguments($method, $args, $message);
  781. $args = $this->_replaceWildcards($args);
  782. $message .= Mock::getExpectationLine();
  783. $this->_expected_args[strtolower($method)] =
  784. new ParametersExpectation($args, $message);
  785. }
  786. /**
  787. * @deprecated
  788. */
  789. function expectArguments($method, $args, $message = '%s') {
  790. return $this->expect($method, $args, $message);
  791. }
  792. /**
  793. * Sets up an expected call with a set of
  794. * expected parameters in that call. The
  795. * expected call count will be adjusted if it
  796. * is set too low to reach this call.
  797. * @param integer $timing Number of calls in the future at
  798. * which to test. Next call is 0.
  799. * @param string $method Method call to test.
  800. * @param array $args Expected parameters for the call
  801. * including wildcards.
  802. * @param string $message Overridden message.
  803. * @access public
  804. */
  805. function expectAt($timing, $method, $args, $message = '%s') {
  806. $this->_dieOnNoMethod($method, 'set expected arguments at time');
  807. $this->_checkArgumentsIsArray($args, 'set expected arguments at time');
  808. $args = $this->_replaceWildcards($args);
  809. if (! isset($this->_expected_args_at[$timing])) {
  810. $this->_expected_args_at[$timing] = array();
  811. }
  812. $method = strtolower($method);
  813. $message .= Mock::getExpectationLine();
  814. $this->_expected_args_at[$timing][$method] =
  815. new ParametersExpectation($args, $message);
  816. }
  817. /**
  818. * @deprecated
  819. */
  820. function expectArgumentsAt($timing, $method, $args, $message = '%s') {
  821. return $this->expectAt($timing, $method, $args, $message);
  822. }
  823. /**
  824. * Sets an expectation for the number of times
  825. * a method will be called. The tally method
  826. * is used to check this.
  827. * @param string $method Method call to test.
  828. * @param integer $count Number of times it should
  829. * have been called at tally.
  830. * @param string $message Overridden message.
  831. * @access public
  832. */
  833. function expectCallCount($method, $count, $message = '%s') {
  834. $this->_dieOnNoMethod($method, 'set expected call count');
  835. $message .= Mock::getExpectationLine();
  836. $this->_expected_counts[strtolower($method)] =
  837. new CallCountExpectation($method, $count, $message);
  838. }
  839. /**
  840. * Sets the number of times a method may be called
  841. * before a test failure is triggered.
  842. * @param string $method Method call to test.
  843. * @param integer $count Most number of times it should
  844. * have been called.
  845. * @param string $message Overridden message.
  846. * @access public
  847. */
  848. function expectMaximumCallCount($method, $count, $message = '%s') {
  849. $this->_dieOnNoMethod($method, 'set maximum call count');
  850. $message .= Mock::getExpectationLine();
  851. $this->_max_counts[strtolower($method)] =
  852. new MaximumCallCountExpectation($method, $count, $message);
  853. }
  854. /**
  855. * Sets the number of times to call a method to prevent
  856. * a failure on the tally.
  857. * @param string $method Method call to test.
  858. * @param integer $count Least number of times it should
  859. * have been called.
  860. * @param string $message Overridden message.
  861. * @access public
  862. */
  863. function expectMinimumCallCount($method, $count, $message = '%s') {
  864. $this->_dieOnNoMethod($method, 'set minimum call count');
  865. $message .= Mock::getExpectationLine();
  866. $this->_expected_counts[strtolower($method)] =
  867. new MinimumCallCountExpectation($method, $count, $message);
  868. }
  869. /**
  870. * Convenience method for barring a method
  871. * call.
  872. * @param string $method Method call to ban.
  873. * @param string $message Overridden message.
  874. * @access public
  875. */
  876. function expectNever($method, $message = '%s') {
  877. $this->expectMaximumCallCount($method, 0, $message);
  878. }
  879. /**
  880. * Convenience method for a single method
  881. * call.
  882. * @param string $method Method call to track.
  883. * @param array $args Expected argument list or
  884. * false for any arguments.
  885. * @param string $message Overridden message.
  886. * @access public
  887. */
  888. function expectOnce($method, $args = false, $message = '%s') {
  889. $this->expectCallCount($method, 1, $message);
  890. if ($args !== false) {
  891. $this->expect($method, $args, $message);
  892. }
  893. }
  894. /**
  895. * Convenience method for requiring a method
  896. * call.
  897. * @param string $method Method call to track.
  898. * @param array $args Expected argument list or
  899. * false for any arguments.
  900. * @param string $message Overridden message.
  901. * @access public
  902. */
  903. function expectAtLeastOnce($method, $args = false, $message = '%s') {
  904. $this->expectMinimumCallCount($method, 1, $message);
  905. if ($args !== false) {
  906. $this->expect($method, $args, $message);
  907. }
  908. }
  909. /**
  910. * Sets up a trigger to throw an exception upon the
  911. * method call.
  912. * @param string $method Method name to throw on.
  913. */
  914. function throwOn($method, $exception = false, $args = false) {
  915. $this->_dieOnNoMethod($method, "throw on");
  916. $this->_actions->register($method, $args,
  917. new SimpleThrower($exception ? $exception : new Exception()));
  918. }
  919. /**
  920. * Sets up a trigger to throw an exception upon the
  921. * method call.
  922. */
  923. function throwAt($timing, $method, $exception = false, $args = false) {
  924. $this->_dieOnNoMethod($method, "throw at");
  925. $this->_actions->registerAt($timing, $method, $args,
  926. new SimpleThrower($exception ? $exception : new Exception()));
  927. }
  928. /**
  929. * Sets up a trigger to throw an error upon the
  930. * method call.
  931. */
  932. function errorOn($method, $error = 'A mock error', $args = false, $severity = E_USER_ERROR) {
  933. $this->_dieOnNoMethod($method, "error on");
  934. $this->_actions->register($method, $args, new SimpleErrorThrower($error, $severity));
  935. }
  936. /**
  937. * Sets up a trigger to throw an error upon the
  938. * method call.
  939. */
  940. function errorAt($timing, $method, $error = 'A mock error', $args = false, $severity = E_USER_ERROR) {
  941. $this->_dieOnNoMethod($method, "error at");
  942. $this->_actions->registerAt($timing, $method, $args, new SimpleErrorThrower($error, $severity));
  943. }
  944. /**
  945. * @deprecated
  946. */
  947. function tally() {
  948. }
  949. /**
  950. * Receives event from unit test that the current
  951. * test method has finished. Totals up the call
  952. * counts and triggers a test assertion if a test
  953. * is present for expected call counts.
  954. * @param string $test_method Current method name.
  955. * @param SimpleTestCase $test Test to send message to.
  956. * @access public
  957. */
  958. function atTestEnd($test_method, &$test) {
  959. foreach ($this->_expected_counts as $method => $expectation) {
  960. $test->assert($expectation, $this->getCallCount($method));
  961. }
  962. foreach ($this->_max_counts as $method => $expectation) {
  963. if ($expectation->test($this->getCallCount($method))) {
  964. $test->assert($expectation, $this->getCallCount($method));
  965. }
  966. }
  967. }
  968. /**
  969. * Returns the expected value for the method name
  970. * and checks expectations. Will generate any
  971. * test assertions as a result of expectations
  972. * if there is a test present.
  973. * @param string $method Name of method to simulate.
  974. * @param array $args Arguments as an array.
  975. * @return mixed Stored return.
  976. * @access private
  977. */
  978. function &_invoke($method, $args) {
  979. $method = strtolower($method);
  980. $step = $this->getCallCount($method);
  981. $this->_addCall($method, $args);
  982. $this->_checkExpectations($method, $args, $step);
  983. $result = &$this->_emulateCall($method, $args, $step);
  984. return $result;
  985. }
  986. /**
  987. * Finds the return value matching the incoming
  988. * arguments. If there is no matching value found
  989. * then an error is triggered.
  990. * @param string $method Method name.
  991. * @param array $args Calling arguments.
  992. * @param integer $step Current position in the
  993. * call history.
  994. * @return mixed Stored return or other action.
  995. * @access protected
  996. */
  997. function &_emulateCall($method, $args, $step) {
  998. return $this->_actions->respond($step, $method, $args);
  999. }
  1000. /**
  1001. * Tests the arguments against expectations.
  1002. * @param string $method Method to check.
  1003. * @param array $args Argument list to match.
  1004. * @param integer $timing The position of this call
  1005. * in the call history.
  1006. * @access private
  1007. */
  1008. function _checkExpectations($method, $args, $timing) {
  1009. $test = &$this->_getCurrentTestCase();
  1010. if (isset($this->_max_counts[$method])) {
  1011. if (! $this->_max_counts[$method]->test($timing + 1)) {
  1012. $test->assert($this->_max_counts[$method], $timing + 1);
  1013. }
  1014. }
  1015. if (isset($this->_expected_args_at[$timing][$method])) {
  1016. $test->assert(
  1017. $this->_expected_args_at[$timing][$method],
  1018. $args,
  1019. "Mock method [$method] at [$timing] -> %s");
  1020. } elseif (isset($this->_expected_args[$method])) {
  1021. $test->assert(
  1022. $this->_expected_args[$method],
  1023. $args,
  1024. "Mock method [$method] -> %s");
  1025. }
  1026. }
  1027. }
  1028. /**
  1029. * Static methods only service class for code generation of
  1030. * mock objects.
  1031. * @package SimpleTest
  1032. * @subpackage MockObjects
  1033. */
  1034. class Mock {
  1035. /**
  1036. * Factory for mock object classes.
  1037. * @access public
  1038. */
  1039. function Mock() {
  1040. trigger_error('Mock factory methods are static.');
  1041. }
  1042. /**
  1043. * Clones a class' interface and creates a mock version
  1044. * that can have return values and expectations set.
  1045. * @param string $class Class to clone.
  1046. * @param string $mock_class New class name. Default is
  1047. * the old name with "Mock"
  1048. * prepended.
  1049. * @param array $methods Additional methods to add beyond
  1050. * those in the cloned class. Use this
  1051. * to emulate the dynamic addition of
  1052. * methods in the cloned class or when
  1053. * the class hasn't been written yet.
  1054. * @static
  1055. * @access public
  1056. */
  1057. function generate($class, $mock_class = false, $methods = false) {
  1058. $generator = new MockGenerator($class, $mock_class);
  1059. return $generator->generateSubclass($methods);
  1060. }
  1061. /**
  1062. * Generates a version of a class with selected
  1063. * methods mocked only. Inherits the old class
  1064. * and chains the mock methods of an aggregated
  1065. * mock object.
  1066. * @param string $class Class to clone.
  1067. * @param string $mock_class New class name.
  1068. * @param array $methods Methods to be overridden
  1069. * with mock versions.
  1070. * @static
  1071. * @access public
  1072. */
  1073. function generatePartial($class, $mock_class, $methods) {
  1074. $generator = new MockGenerator($class, $mock_class);
  1075. return $generator->generatePartial($methods);
  1076. }
  1077. /**
  1078. * Uses a stack trace to find the line of an assertion.
  1079. * @access public
  1080. * @static
  1081. */
  1082. function getExpectationLine() {
  1083. $trace = new SimpleStackTrace(array('expect'));
  1084. return $trace->traceMethod();
  1085. }
  1086. }
  1087. /**
  1088. * @package SimpleTest
  1089. * @subpackage MockObjects
  1090. * @deprecated
  1091. */
  1092. class Stub extends Mock {
  1093. }
  1094. /**
  1095. * Service class for code generation of mock objects.
  1096. * @package SimpleTest
  1097. * @subpackage MockObjects
  1098. */
  1099. class MockGenerator {
  1100. var $_class;
  1101. var $_mock_class;
  1102. var $_mock_base;
  1103. var $_reflection;
  1104. /**
  1105. * Builds initial reflection object.
  1106. * @param string $class Class to be mocked.
  1107. * @param string $mock_class New class with identical interface,
  1108. * but no behaviour.
  1109. */
  1110. function MockGenerator($class, $mock_class) {
  1111. $this->_class = $class;
  1112. $this->_mock_class = $mock_class;
  1113. if (! $this->_mock_class) {
  1114. $this->_mock_class = 'Mock' . $this->_class;
  1115. }
  1116. $this->_mock_base = SimpleTest::getMockBaseClass();
  1117. $this->_reflection = new SimpleReflection($this->_class);
  1118. }
  1119. /**
  1120. * Clones a class' interface and creates a mock version
  1121. * that can have return values and expectations set.
  1122. * @param array $methods Additional methods to add beyond
  1123. * those in th cloned class. Use this
  1124. * to emulate the dynamic addition of
  1125. * methods in the cloned class or when
  1126. * the class hasn't been written yet.
  1127. * @access public
  1128. */
  1129. function generate($methods) {
  1130. if (! $this->_reflection->classOrInterfaceExists()) {
  1131. return false;
  1132. }
  1133. $mock_reflection = new SimpleReflection($this->_mock_class);
  1134. if ($mock_reflection->classExistsSansAutoload()) {
  1135. return false;
  1136. }
  1137. $code = $this->_createClassCode($methods ? $methods : array());
  1138. return eval("$code return \$code;");
  1139. }
  1140. /**
  1141. * Subclasses a class and overrides every method with a mock one
  1142. * that can have return values and expectations set. Chains
  1143. * to an aggregated SimpleMock.
  1144. * @param array $methods Additional methods to add beyond
  1145. * those in the cloned class. Use this
  1146. * to emulate the dynamic addition of
  1147. * methods in the cloned class or when
  1148. * the class hasn't been written yet.
  1149. * @access public
  1150. */
  1151. function generateSubclass($methods) {
  1152. if (! $this->_reflection->classOrInterfaceExists()) {
  1153. return false;
  1154. }
  1155. $mock_reflection = new SimpleReflection($this->_mock_class);
  1156. if ($mock_reflection->classExistsSansAutoload()) {
  1157. return false;
  1158. }
  1159. if ($this->_reflection->isInterface() || $this->_reflection->hasFinal()) {
  1160. $code = $this->_createClassCode($methods ? $methods : array());
  1161. return eval("$code return \$code;");
  1162. } else {
  1163. $code = $this->_createSubclassCode($methods ? $methods : array());
  1164. return eval("$code return \$code;");
  1165. }
  1166. }
  1167. /**
  1168. * Generates a version of a class with selected
  1169. * methods mocked only. Inherits the old class
  1170. * and chains the mock methods of an aggregated
  1171. * mock object.
  1172. * @param array $methods Methods to be overridden
  1173. * with mock versions.
  1174. * @access public
  1175. */
  1176. function generatePartial($methods) {
  1177. if (! $this->_reflection->classExists($this->_class)) {
  1178. return false;
  1179. }
  1180. $mock_reflection = new SimpleReflection($this->_mock_class);
  1181. if ($mock_reflection->classExistsSansAutoload()) {
  1182. trigger_error('Partial mock class [' . $this->_mock_class . '] already exists');
  1183. return false;
  1184. }
  1185. $code = $this->_extendClassCode($methods);
  1186. return eval("$code return \$code;");
  1187. }
  1188. /**
  1189. * The new mock class code as a string.
  1190. * @param array $methods Additional methods.
  1191. * @return string Code for new mock class.
  1192. * @access private
  1193. */
  1194. function _createClassCode($methods) {
  1195. $implements = '';
  1196. $interfaces = $this->_reflection->getInterfaces();
  1197. if (function_exists('spl_classes')) {
  1198. $interfaces = array_diff($interfaces, array('Traversable'));
  1199. }
  1200. if (count($interfaces) > 0) {
  1201. $implements = 'implements ' . implode(', ', $interfaces);
  1202. }
  1203. $code = "class " . $this->_mock_class . " extends " . $this->_mock_base . " $implements {\n";
  1204. $code .= " function " . $this->_mock_class . "() {\n";
  1205. $code .= " \$this->" . $this->_mock_base . "();\n";
  1206. $code .= " }\n";
  1207. if (in_array('__construct', $this->_reflection->getMethods())) {
  1208. $code .= " " . $this->_reflection->getSignature('__construct') . " {\n";
  1209. $code .= " \$this->" . $this->_mock_base . "();\n";
  1210. $code .= " }\n";
  1211. }
  1212. $code .= $this->_createHandlerCode($methods);
  1213. $code .= "}\n";
  1214. return $code;
  1215. }
  1216. /**
  1217. * The new mock class code as a string. The mock will
  1218. * be a subclass of the original mocked class.
  1219. * @param array $methods Additional methods.
  1220. * @return string Code for new mock class.
  1221. * @access private
  1222. */
  1223. function _createSubclassCode($methods) {
  1224. $code = "class " . $this->_mock_class . " extends " . $this->_class . " {\n";
  1225. $code .= " var \$_mock;\n";
  1226. $code .= $this->_addMethodList(array_merge($methods, $this->_reflection->getMethods()));
  1227. $code .= "\n";
  1228. $code .= " function " . $this->_mock_class . "() {\n";
  1229. $code .= " \$this->_mock = &new " . $this->_mock_base . "();\n";
  1230. $code .= " \$this->_mock->disableExpectationNameChecks();\n";
  1231. $code .= " }\n";
  1232. $code .= $this->_chainMockReturns();
  1233. $code .= $this->_chainMockExpectations();
  1234. $code .= $this->_chainThrowMethods();
  1235. $code .= $this->_overrideMethods($this->_reflection->getMethods());
  1236. $code .= $this->_createNewMethodCode($methods);
  1237. $code .= "}\n";
  1238. return $code;
  1239. }
  1240. /**
  1241. * The extension class code as a string. The class
  1242. * composites a mock object and chains mocked methods
  1243. * to it.
  1244. * @param array $methods Mocked methods.
  1245. * @return string Code for a new class.
  1246. * @access private
  1247. */
  1248. function _extendClassCode($methods) {
  1249. $code = "class " . $this->_mock_class . " extends " . $this->_class . " {\n";
  1250. $code .= " var \$_mock;\n";
  1251. $code .= $this->_addMethodList($methods);
  1252. $code .= "\n";
  1253. $code .= " function " . $this->_mock_class . "() {\n";
  1254. $code .= " \$this->_mock = &new " . $this->_mock_base . "();\n";
  1255. $code .= " \$this->_mock->disableExpectationNameChecks();\n";
  1256. $code .= " }\n";
  1257. $code .= $this->_chainMockReturns();
  1258. $code .= $this->_chainMockExpectations();
  1259. $code .= $this->_chainThrowMethods();
  1260. $code .= $this->_overrideMethods($methods);
  1261. $code .= "}\n";
  1262. return $code;
  1263. }
  1264. /**
  1265. * Creates code within a class to generate replaced
  1266. * methods. All methods call the _invoke() handler
  1267. * with the method name and the arguments in an
  1268. * array.
  1269. * @param array $methods Additional methods.
  1270. * @access private
  1271. */
  1272. function _createHandlerCode($methods) {
  1273. $code = '';
  1274. $methods = array_merge($methods, $this->_reflection->getMethods());
  1275. foreach ($methods as $method) {
  1276. if ($this->_isConstructor($method)) {
  1277. continue;
  1278. }
  1279. $mock_reflection = new SimpleReflection($this->_mock_base);
  1280. if (in_array($method, $mock_reflection->getMethods())) {
  1281. continue;
  1282. }
  1283. $code .= " " . $this->_reflection->getSignature($method) . " {\n";
  1284. $code .= " \$args = func_get_args();\n";
  1285. $code .= " \$result = &\$this->_invoke(\"$method\", \$args);\n";
  1286. $code .= " return \$result;\n";
  1287. $code .= " }\n";
  1288. }
  1289. return $code;
  1290. }
  1291. /**
  1292. * Creates code within a class to generate a new
  1293. * methods. All methods call the _invoke() handler
  1294. * on the internal mock with the method name and
  1295. * the arguments in an array.
  1296. * @param array $methods Additional methods.
  1297. * @access private
  1298. */
  1299. function _createNewMethodCode($methods) {
  1300. $code = '';
  1301. foreach ($methods as $method) {
  1302. if ($this->_isConstructor($method)) {
  1303. continue;
  1304. }
  1305. $mock_reflection = new SimpleReflection($this->_mock_base);
  1306. if (in_array($method, $mock_reflection->getMethods())) {
  1307. continue;
  1308. }
  1309. $code .= " " . $this->_reflection->getSignature($method) . " {\n";
  1310. $code .= " \$args = func_get_args();\n";
  1311. $code .= " \$result = &\$this->_mock->_invoke(\"$method\", \$args);\n";
  1312. $code .= " return \$result;\n";
  1313. $code .= " }\n";
  1314. }
  1315. return $code;
  1316. }
  1317. /**
  1318. * Tests to see if a special PHP method is about to
  1319. * be stubbed by mistake.
  1320. * @param string $method Method name.
  1321. * @return boolean True if special.
  1322. * @access private
  1323. */
  1324. function _isConstructor($method) {
  1325. return in_array(
  1326. strtolower($meth

Large files files are truncated, but you can click here to view the full file