PageRenderTime 60ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/test/simpletest/mock_objects.php

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

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