mock_objects.php 58KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630
  1. <?php
  2. /**
  3. * base include file for SimpleTest
  4. * @package SimpleTest
  5. * @subpackage MockObjects
  6. * @version $Id: mock_objects.php 1788 2008-04-27 11:01:59Z pp11 $
  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 setReturnValue($method, $value, $args = false) {
  774. $this->dieOnNoMethod($method, "set return value");
  775. $this->actions->register($method, $args, new SimpleByValue($value));
  776. }
  777. /**
  778. * Sets a return for a parameter list that will
  779. * be passed by value only when the required call count
  780. * is reached.
  781. * @param integer $timing Number of calls in the future
  782. * to which the result applies. If
  783. * not set then all calls will return
  784. * the value.
  785. * @param string $method Method name.
  786. * @param mixed $value Result of call passed by value.
  787. * @param array $args List of parameters to match
  788. * including wildcards.
  789. * @access public
  790. */
  791. function setReturnValueAt($timing, $method, $value, $args = false) {
  792. $this->dieOnNoMethod($method, "set return value sequence");
  793. $this->actions->registerAt($timing, $method, $args, new SimpleByValue($value));
  794. }
  795. /**
  796. * Sets a return for a parameter list that will
  797. * be passed by reference for all calls.
  798. * @param string $method Method name.
  799. * @param mixed $reference Result of the call will be this object.
  800. * @param array $args List of parameters to match
  801. * including wildcards.
  802. * @access public
  803. */
  804. function setReturnReference($method, &$reference, $args = false) {
  805. $this->dieOnNoMethod($method, "set return reference");
  806. $this->actions->register($method, $args, new SimpleByReference($reference));
  807. }
  808. /**
  809. * Sets a return for a parameter list that will
  810. * be passed by value only when the required call count
  811. * is reached.
  812. * @param integer $timing Number of calls in the future
  813. * to which the result applies. If
  814. * not set then all calls will return
  815. * the value.
  816. * @param string $method Method name.
  817. * @param mixed $reference Result of the call will be this object.
  818. * @param array $args List of parameters to match
  819. * including wildcards.
  820. * @access public
  821. */
  822. function setReturnReferenceAt($timing, $method, &$reference, $args = false) {
  823. $this->dieOnNoMethod($method, "set return reference sequence");
  824. $this->actions->registerAt($timing, $method, $args, new SimpleByReference($reference));
  825. }
  826. /**
  827. * Sets up an expected call with a set of
  828. * expected parameters in that call. All
  829. * calls will be compared to these expectations
  830. * regardless of when the call is made.
  831. * @param string $method Method call to test.
  832. * @param array $args Expected parameters for the call
  833. * including wildcards.
  834. * @param string $message Overridden message.
  835. * @access public
  836. */
  837. function expect($method, $args, $message = '%s') {
  838. $this->dieOnNoMethod($method, 'set expected arguments');
  839. $this->checkArgumentsIsArray($args, 'set expected arguments');
  840. $this->expectations->expectArguments($method, $args, $message);
  841. $args = $this->replaceWildcards($args);
  842. $message .= Mock::getExpectationLine();
  843. $this->expected_args[strtolower($method)] =
  844. new ParametersExpectation($args, $message);
  845. }
  846. /**
  847. * Sets up an expected call with a set of
  848. * expected parameters in that call. The
  849. * expected call count will be adjusted if it
  850. * is set too low to reach this call.
  851. * @param integer $timing Number of calls in the future at
  852. * which to test. Next call is 0.
  853. * @param string $method Method call to test.
  854. * @param array $args Expected parameters for the call
  855. * including wildcards.
  856. * @param string $message Overridden message.
  857. * @access public
  858. */
  859. function expectAt($timing, $method, $args, $message = '%s') {
  860. $this->dieOnNoMethod($method, 'set expected arguments at time');
  861. $this->checkArgumentsIsArray($args, 'set expected arguments at time');
  862. $args = $this->replaceWildcards($args);
  863. if (! isset($this->expected_args_at[$timing])) {
  864. $this->expected_args_at[$timing] = array();
  865. }
  866. $method = strtolower($method);
  867. $message .= Mock::getExpectationLine();
  868. $this->expected_args_at[$timing][$method] =
  869. new ParametersExpectation($args, $message);
  870. }
  871. /**
  872. * Sets an expectation for the number of times
  873. * a method will be called. The tally method
  874. * is used to check this.
  875. * @param string $method Method call to test.
  876. * @param integer $count Number of times it should
  877. * have been called at tally.
  878. * @param string $message Overridden message.
  879. * @access public
  880. */
  881. function expectCallCount($method, $count, $message = '%s') {
  882. $this->dieOnNoMethod($method, 'set expected call count');
  883. $message .= Mock::getExpectationLine();
  884. $this->expected_counts[strtolower($method)] =
  885. new CallCountExpectation($method, $count, $message);
  886. }
  887. /**
  888. * Sets the number of times a method may be called
  889. * before a test failure is triggered.
  890. * @param string $method Method call to test.
  891. * @param integer $count Most number of times it should
  892. * have been called.
  893. * @param string $message Overridden message.
  894. * @access public
  895. */
  896. function expectMaximumCallCount($method, $count, $message = '%s') {
  897. $this->dieOnNoMethod($method, 'set maximum call count');
  898. $message .= Mock::getExpectationLine();
  899. $this->max_counts[strtolower($method)] =
  900. new MaximumCallCountExpectation($method, $count, $message);
  901. }
  902. /**
  903. * Sets the number of times to call a method to prevent
  904. * a failure on the tally.
  905. * @param string $method Method call to test.
  906. * @param integer $count Least number of times it should
  907. * have been called.
  908. * @param string $message Overridden message.
  909. * @access public
  910. */
  911. function expectMinimumCallCount($method, $count, $message = '%s') {
  912. $this->dieOnNoMethod($method, 'set minimum call count');
  913. $message .= Mock::getExpectationLine();
  914. $this->expected_counts[strtolower($method)] =
  915. new MinimumCallCountExpectation($method, $count, $message);
  916. }
  917. /**
  918. * Convenience method for barring a method
  919. * call.
  920. * @param string $method Method call to ban.
  921. * @param string $message Overridden message.
  922. * @access public
  923. */
  924. function expectNever($method, $message = '%s') {
  925. $this->expectMaximumCallCount($method, 0, $message);
  926. }
  927. /**
  928. * Convenience method for a single method
  929. * call.
  930. * @param string $method Method call to track.
  931. * @param array $args Expected argument list or
  932. * false for any arguments.
  933. * @param string $message Overridden message.
  934. * @access public
  935. */
  936. function expectOnce($method, $args = false, $message = '%s') {
  937. $this->expectCallCount($method, 1, $message);
  938. if ($args !== false) {
  939. $this->expect($method, $args, $message);
  940. }
  941. }
  942. /**
  943. * Convenience method for requiring a method
  944. * call.
  945. * @param string $method Method call to track.
  946. * @param array $args Expected argument list or
  947. * false for any arguments.
  948. * @param string $message Overridden message.
  949. * @access public
  950. */
  951. function expectAtLeastOnce($method, $args = false, $message = '%s') {
  952. $this->expectMinimumCallCount($method, 1, $message);
  953. if ($args !== false) {
  954. $this->expect($method, $args, $message);
  955. }
  956. }
  957. /**
  958. * Sets up a trigger to throw an exception upon the
  959. * method call.
  960. * @param string $method Method name to throw on.
  961. */
  962. function throwOn($method, $exception = false, $args = false) {
  963. $this->dieOnNoMethod($method, "throw on");
  964. $this->actions->register($method, $args,
  965. new SimpleThrower($exception ? $exception : new Exception()));
  966. }
  967. /**
  968. * Sets up a trigger to throw an exception upon the
  969. * method call.
  970. */
  971. function throwAt($timing, $method, $exception = false, $args = false) {
  972. $this->dieOnNoMethod($method, "throw at");
  973. $this->actions->registerAt($timing, $method, $args,
  974. new SimpleThrower($exception ? $exception : new Exception()));
  975. }
  976. /**
  977. * Sets up a trigger to throw an error upon the
  978. * method call.
  979. */
  980. function errorOn($method, $error = 'A mock error', $args = false, $severity = E_USER_ERROR) {
  981. $this->dieOnNoMethod($method, "error on");
  982. $this->actions->register($method, $args, new SimpleErrorThrower($error, $severity));
  983. }
  984. /**
  985. * Sets up a trigger to throw an error upon the
  986. * method call.
  987. */
  988. function errorAt($timing, $method, $error = 'A mock error', $args = false, $severity = E_USER_ERROR) {
  989. $this->dieOnNoMethod($method, "error at");
  990. $this->actions->registerAt($timing, $method, $args, new SimpleErrorThrower($error, $severity));
  991. }
  992. /**
  993. * Receives event from unit test that the current
  994. * test method has finished. Totals up the call
  995. * counts and triggers a test assertion if a test
  996. * is present for expected call counts.
  997. * @param string $test_method Current method name.
  998. * @param SimpleTestCase $test Test to send message to.
  999. * @access public
  1000. */
  1001. function atTestEnd($test_method, &$test) {
  1002. foreach ($this->expected_counts as $method => $expectation) {
  1003. $test->assert($expectation, $this->getCallCount($method));
  1004. }
  1005. foreach ($this->max_counts as $method => $expectation) {
  1006. if ($expectation->test($this->getCallCount($method))) {
  1007. $test->assert($expectation, $this->getCallCount($method));
  1008. }
  1009. }
  1010. }
  1011. /**
  1012. * Returns the expected value for the method name
  1013. * and checks expectations. Will generate any
  1014. * test assertions as a result of expectations
  1015. * if there is a test present.
  1016. * @param string $method Name of method to simulate.
  1017. * @param array $args Arguments as an array.
  1018. * @return mixed Stored return.
  1019. * @access private
  1020. */
  1021. function &invoke($method, $args) {
  1022. $method = strtolower($method);
  1023. $step = $this->getCallCount($method);
  1024. $this->addCall($method, $args);
  1025. $this->checkExpectations($method, $args, $step);
  1026. $was = $this->disableEStrict();
  1027. try {
  1028. $result = &$this->emulateCall($method, $args, $step);
  1029. } catch (Exception $e) {
  1030. $this->restoreEStrict($was);
  1031. throw $e;
  1032. }
  1033. $this->restoreEStrict($was);
  1034. return $result;
  1035. }
  1036. /**
  1037. * Finds the return value matching the incoming
  1038. * arguments. If there is no matching value found
  1039. * then an error is triggered.
  1040. * @param string $method Method name.
  1041. * @param array $args Calling arguments.
  1042. * @param integer $step Current position in the
  1043. * call history.
  1044. * @return mixed Stored return or other action.
  1045. * @access protected
  1046. */
  1047. protected function &emulateCall($method, $args, $step) {
  1048. return $this->actions->respond($step, $method, $args);
  1049. }
  1050. /**
  1051. * Tests the arguments against expectations.
  1052. * @param string $method Method to check.
  1053. * @param array $args Argument list to match.
  1054. * @param integer $timing The position of this call
  1055. * in the call history.
  1056. * @access private
  1057. */
  1058. protected function checkExpectations($method, $args, $timing) {
  1059. $test = $this->getCurrentTestCase();
  1060. if (isset($this->max_counts[$method])) {
  1061. if (! $this->max_counts[$method]->test($timing + 1)) {
  1062. $test->assert($this->max_counts[$method], $timing + 1);
  1063. }
  1064. }
  1065. if (isset($this->expected_args_at[$timing][$method])) {
  1066. $test->assert(
  1067. $this->expected_args_at[$timing][$method],
  1068. $args,
  1069. "Mock method [$method] at [$timing] -> %s");
  1070. } elseif (isset($this->expected_args[$method])) {
  1071. $test->assert(
  1072. $this->expected_args[$method],
  1073. $args,
  1074. "Mock method [$method] -> %s");
  1075. }
  1076. }
  1077. private function disableEStrict() {
  1078. $was = error_reporting();
  1079. error_reporting($was & ~E_STRICT);
  1080. return $was;
  1081. }
  1082. private function restoreEStrict($was) {
  1083. error_reporting($was);
  1084. }
  1085. }
  1086. /**
  1087. * Static methods only service class for code generation of
  1088. * mock objects.
  1089. * @package SimpleTest
  1090. * @subpackage MockObjects
  1091. */
  1092. class Mock {
  1093. /**
  1094. * Factory for mock object classes.
  1095. * @access public
  1096. */
  1097. function __construct() {
  1098. trigger_error('Mock factory methods are static.');
  1099. }
  1100. /**
  1101. * Clones a class' interface and creates a mock version
  1102. * that can have return values and expectations set.
  1103. * @param string $class Class to clone.
  1104. * @param string $mock_class New class name. Default is
  1105. * the old name with "Mock"
  1106. * prepended.
  1107. * @param array $methods Additional methods to add beyond
  1108. * those in the cloned class. Use this
  1109. * to emulate the dynamic addition of
  1110. * methods in the cloned class or when
  1111. * the class hasn't been written yet.sta
  1112. * @access public
  1113. */
  1114. static function generate($class, $mock_class = false, $methods = false) {
  1115. $generator = new MockGenerator($class, $mock_class);
  1116. return @$generator->generateSubclass($methods);
  1117. }
  1118. /**
  1119. * Generates a version of a class with selected
  1120. * methods mocked only. Inherits the old class
  1121. * and chains the mock methods of an aggregated
  1122. * mock object.
  1123. * @param string $class Class to clone.
  1124. * @param string $mock_class New class name.
  1125. * @param array $methods Methods to be overridden
  1126. * with mock versions.
  1127. * @access public
  1128. */
  1129. static function generatePartial($class, $mock_class, $methods) {
  1130. $generator = new MockGenerator($class, $mock_class);
  1131. return @$generator->generatePartial($methods);
  1132. }
  1133. /**
  1134. * Uses a stack trace to find the line of an assertion.
  1135. * @access public
  1136. */
  1137. static function getExpectationLine() {
  1138. $trace = new SimpleStackTrace(array('expect'));
  1139. return $trace->traceMethod();
  1140. }
  1141. }
  1142. /**
  1143. * Service class for code generation of mock objects.
  1144. * @package SimpleTest
  1145. * @subpackage MockObjects
  1146. */
  1147. class MockGenerator {
  1148. private $class;
  1149. private $mock_class;
  1150. private $mock_base;
  1151. private $reflection;
  1152. /**
  1153. * Builds initial reflection object.
  1154. * @param string $class Class to be mocked.
  1155. * @param string $mock_class New class with identical interface,
  1156. * but no behaviour.
  1157. */
  1158. function __construct($class, $mock_class) {
  1159. $this->class = $class;
  1160. $this->mock_class = $mock_class;
  1161. if (! $this->mock_class) {
  1162. $this->mock_class = 'Mock' . $this->class;
  1163. }
  1164. $this->mock_base = SimpleTest::getMockBaseClass();
  1165. $this->reflection = new SimpleReflection($this->class);
  1166. }
  1167. /**
  1168. * Clones a class' interface and creates a mock version
  1169. * that can have return values and expectations set.
  1170. * @param array $methods Additional methods to add beyond
  1171. * those in th cloned class. Use this
  1172. * to emulate the dynamic addition of
  1173. * methods in the cloned class or when
  1174. * the class hasn't been written yet.
  1175. * @access public
  1176. */
  1177. function generate($methods) {
  1178. if (! $this->reflection->classOrInterfaceExists()) {
  1179. return false;
  1180. }
  1181. $mock_reflection = new SimpleReflection($this->mock_class);
  1182. if ($mock_reflection->classExistsSansAutoload()) {
  1183. return false;
  1184. }
  1185. $code = $this->createClassCode($methods ? $methods : array());
  1186. return eval("$code return \$code;");
  1187. }
  1188. /**
  1189. * Subclasses a class and overrides every method with a mock one
  1190. * that can have return values and expectations set. Chains
  1191. * to an aggregated SimpleMock.
  1192. * @param array $methods Additional methods to add beyond
  1193. * those in the cloned class. Use this
  1194. * to emulate the dynamic addition of
  1195. * methods in the cloned class or when
  1196. * the class hasn't been written yet.
  1197. * @access public
  1198. */
  1199. function generateSubclass($methods) {
  1200. if (! $this->reflection->classOrInterfaceExists()) {
  1201. return false;
  1202. }
  1203. $mock_reflection = new SimpleReflection($this->mock_class);
  1204. if ($mock_reflection->classExistsSansAutoload()) {
  1205. return false;
  1206. }
  1207. if ($this->reflection->isInterface() || $this->reflection->hasFinal()) {
  1208. $code = $this->createClassCode($methods ? $methods : array());
  1209. return eval("$code return \$code;");
  1210. } else {
  1211. $code = $this->createSubclassCode($methods ? $methods : array());
  1212. return eval("$code return \$code;");
  1213. }
  1214. }
  1215. /**
  1216. * Generates a version of a class with selected
  1217. * methods mocked only. Inherits the old class
  1218. * and chains the mock methods of an aggregated
  1219. * mock object.
  1220. * @param array $methods Methods to be overridden
  1221. * with mock versions.
  1222. * @access public
  1223. */
  1224. function generatePartial($methods) {
  1225. if (! $this->reflection->classExists($this->class)) {
  1226. return false;
  1227. }
  1228. $mock_reflection = new SimpleReflection($this->mock_class);
  1229. if ($mock_reflection->classExistsSansAutoload()) {
  1230. trigger_error('Partial mock class [' . $this->mock_class . '] already exists');
  1231. return false;
  1232. }
  1233. $code = $this->extendClassCode($methods);
  1234. return eval("$code return \$code;");
  1235. }
  1236. /**
  1237. * The new mock class code as a string.
  1238. * @param array $methods Additional methods.
  1239. * @return string Code for new mock class.
  1240. * @access private
  1241. */
  1242. protected function createClassCode($methods) {
  1243. $implements = '';
  1244. $interfaces = $this->reflection->getInterfaces();
  1245. if (function_exists('spl_classes')) {
  1246. $interfaces = array_diff($interfaces, array('Traversable'));
  1247. }
  1248. if (count($interfaces) > 0) {
  1249. $implements = 'implements ' . implode(', ', $interfaces);
  1250. }
  1251. $code = "class " . $this->mock_class . " extends " . $this->mock_base . " $implements {\n";
  1252. $code .= " function " . $this->mock_class . "() {\n";
  1253. $code .= " \$this->" . $this->mock_base . "();\n";
  1254. $code .= " }\n";
  1255. if (in_array('__construct', $this->reflection->getMethods())) {
  1256. $code .= " function __construct() {\n";
  1257. $code .= " \$this->" . $this->mock_base . "();\n";
  1258. $code .= " }\n";
  1259. }
  1260. $code .= $this->createHandlerCode($methods);
  1261. $code .= "}\n";
  1262. return $code;
  1263. }
  1264. /**
  1265. * The new mock class code as a string. The mock will
  1266. * be a subclass of the original mocked class.
  1267. * @param array $methods Additional methods.
  1268. * @return string Code for new mock class.
  1269. * @access private
  1270. */
  1271. protected function createSubclassCode($methods) {
  1272. $code = "class " . $this->mock_class . " extends " . $this->class . " {\n";
  1273. $code .= " public \$mock;\n";
  1274. $code .= $this->addMethodList(array_merge($methods, $this->reflection->getMethods()));
  1275. $code .= "\n";
  1276. $code .= " function " . $this->mock_class . "() {\n";
  1277. $code .= " \$this->mock = new " . $this->mock_base . "();\n";
  1278. $code .= " \$this->mock->disableExpectationNameChecks();\n";
  1279. $code .= " }\n";
  1280. $code .= $this->chainMockReturns();
  1281. $code .= $this->chainMockExpectations();
  1282. $code .= $this->chainThrowMethods();
  1283. $code .= $this->overrideMethods($this->reflection->getMethods());
  1284. $code .= $this->createNewMethodCode($methods);
  1285. $code .= "}\n";
  1286. return $code;
  1287. }
  1288. /**
  1289. * The extension class code as a string. The class
  1290. * composites a mock object and chains mocked methods
  1291. * to it.
  1292. * @param array $methods Mocked methods.
  1293. * @return string Code for a new class.
  1294. * @access private
  1295. */
  1296. protected function extendClassCode($methods) {
  1297. $code = "class " . $this->mock_class . " extends " . $this->class . " {\n";
  1298. $code .= " protected \$mock;\n";
  1299. $code .= $this->addMethodList($methods);
  1300. $code .= "\n";
  1301. $code .= " function " . $this->mock_class . "() {\n";
  1302. $code .= " \$this->mock = new " . $this->mock_base . "();\n";
  1303. $code .= " \$this->mock->disableExpectationNameChecks();\n";
  1304. $code .= " }\n";
  1305. $code .= $this->chainMockReturns();
  1306. $code .= $this->chainMockExpectations();
  1307. $code .= $this->chainThrowMethods();
  1308. $code .= $this->overrideMethods($methods);
  1309. $code .= "}\n";
  1310. return $code;
  1311. }
  1312. /**
  1313. * Creates code within a class to generate replaced
  1314. * methods. All methods call the invoke() handler
  1315. * with the method name and the arguments in an
  1316. * array.
  1317. * @param array $methods Additional methods.
  1318. * @access private
  1319. */
  1320. protected function createHandlerCode($methods) {
  1321. $code = '';
  1322. $methods = array_merge($methods, $this->reflection->getMethods());
  1323. foreach ($methods as $method) {
  1324. if ($this->isConstructor($method)) {
  1325. continue;
  1326. }
  1327. $mock_reflection = new SimpleReflection($this->mock_base);
  1328. if (in_array($method, $mock_reflection->getMethods())) {
  1329. continue;
  1330. }
  1331. $code .= " " . $this->reflection->getSignature($method) . " {\n";
  1332. $code .= " \$args = func_get_args();\n";
  1333. $code .= " \$result = &\$this->invoke(\"$method\", \$args);\n";
  1334. $code .= " return \$result;\n";
  1335. $code .= " }\n";
  1336. }
  1337. return $code;
  1338. }
  1339. /**
  1340. * Creates code within a class to generate a new
  1341. * methods. All methods call the invoke() handler
  1342. * on the internal mock with the method name and
  1343. * the arguments in an array.
  1344. * @param array $methods Additional methods.
  1345. * @access private
  1346. */
  1347. protected function createNewMethodCode($methods) {
  1348. $code = '';
  1349. foreach ($methods as $method) {
  1350. if ($this->isConstructor($method)) {
  1351. continue;
  1352. }
  1353. $mock_reflection = new SimpleReflection($this->mock_base);
  1354. if (in_array($method, $mock_reflection->getMethods())) {
  1355. continue;
  1356. }
  1357. $code .= " " . $this->reflection->getSignature($method) . " {\n";
  1358. $code .= " \$args = func_get_args();\n";
  1359. $code .= " \$result = &\$this->mock->invoke(\"$method\", \$args);\n";
  1360. $code .= " return \$result;\n";
  1361. $code .= " }\n";
  1362. }
  1363. return $code;
  1364. }
  1365. /**
  1366. * Tests to see if a special PHP method is about to
  1367. * be stubbed by mistake.
  1368. * @param string $method Method name.
  1369. * @return boolean True if special.
  1370. * @access private
  1371. */
  1372. protected function isConstructor($method) {
  1373. return in_array(
  1374. strtolower($method),
  1375. array('__construct', '__destruct'));
  1376. }
  1377. /**
  1378. * Creates a list of mocked methods for error checking.
  1379. * @param array $methods Mocked methods.
  1380. * @return string Code for a method list.
  1381. * @access private
  1382. */
  1383. protected function addMethodList($methods) {
  1384. return " protected \$mocked_methods = array('" .
  1385. implode("', '", array_map('strtolower', $methods)) .
  1386. "');\n";
  1387. }
  1388. /**
  1389. * Creates code to abandon the expectation if not mocked.
  1390. * @param string $alias Parameter name of method name.
  1391. * @return string Code for bail out.
  1392. * @access private
  1393. */
  1394. protected function bailOutIfNotMocked($alias) {
  1395. $code = " if (! in_array(strtolower($alias), \$this->mocked_methods)) {\n";
  1396. $code .= " trigger_error(\"Method [$alias] is not mocked\");\n";
  1397. $code .= " \$null = null;\n";
  1398. $code .= " return \$null;\n";
  1399. $code .= " }\n";
  1400. return $code;
  1401. }
  1402. /**
  1403. * Creates source code for chaining to the composited
  1404. * mock object.
  1405. * @return string Code for mock set up.
  1406. * @access private
  1407. */
  1408. protected function chainMockReturns() {
  1409. $code = " function returns(\$method, \$value, \$args = false) {\n";
  1410. $code .= $this->bailOutIfNotMocked("\$method");
  1411. $code .= " \$this->mock->returns(\$method, \$value, \$args);\n";
  1412. $code .= " }\n";
  1413. $code .= " function returnsAt(\$timing, \$method, \$value, \$args = false) {\n";
  1414. $code .= $this->bailOutIfNotMocked("\$method");
  1415. $code .= " \$this->mock->returnsAt(\$timing, \$method, \$value, \$args);\n";
  1416. $code .= " }\n";
  1417. $code .= " function setReturnValue(\$method, \$value, \$args = false) {\n";
  1418. $code .= $this->bailOutIfNotMocked("\$method");
  1419. $code .= " \$this->mock->setReturnValue(\$method, \$value, \$args);\n";
  1420. $code .= " }\n";
  1421. $code .= " function setReturnValueAt(\$timing, \$method, \$value, \$args = false) {\n";
  1422. $code .= $this->bailOutIfNotMocked("\$method");
  1423. $code .= " \$this->mock->setReturnValueAt(\$timing, \$method, \$value, \$args);\n";
  1424. $code .= " }\n";
  1425. $code .= " function setReturnReference(\$method, &\$ref, \$args = false) {\n";
  1426. $code .= $this->bailOutIfNotMocked("\$method");
  1427. $code .= " \$this->mock->setReturnReference(\$method, \$ref, \$args);\n";
  1428. $code .= " }\n";
  1429. $code .= " function setReturnReferenceAt(\$timing, \$method, &\$ref, \$args = false) {\n";
  1430. $code .= $this->bailOutIfNotMocked("\$method");
  1431. $code .= " \$this->mock->setReturnReferenceAt(\$timing, \$method, \$ref, \$args);\n";
  1432. $code .= " }\n";
  1433. return $code;
  1434. }
  1435. /**
  1436. * Creates source code for chaining to an aggregated
  1437. * mock object.
  1438. * @return string Code for expectations.
  1439. * @access private
  1440. */
  1441. protected function chainMockExpectations() {
  1442. $code = " function expect(\$method, \$args = false, \$msg = '%s') {\n";
  1443. $code .= $this->bailOutIfNotMocked("\$method");
  1444. $code .= " \$this->mock->expect(\$method, \$args, \$msg);\n";
  1445. $code .= " }\n";
  1446. $code .= " function expectAt(\$timing, \$method, \$args = false, \$msg = '%s') {\n";
  1447. $code .= $this->bailOutIfNotMocked("\$method");
  1448. $code .= " \$this->mock->expectAt(\$timing, \$method, \$args, \$msg);\n";
  1449. $code .= " }\n";
  1450. $code .= " function expectCallCount(\$method, \$count) {\n";
  1451. $code .= $this->bailOutIfNotMocked("\$method");
  1452. $code .= " \$this->mock->expectCallCount(\$method, \$count, \$msg = '%s');\n";
  1453. $code .= " }\n";
  1454. $code .= " function expectMaximumCallCount(\$method, \$count, \$msg = '%s') {\n";
  1455. $code .= $this->bailOutIfNotMocked("\$method");
  1456. $code .= " \$this->mock->expectMaximumCallCount(\$method, \$count, \$msg = '%s');\n";
  1457. $code .= " }\n";
  1458. $code .= " function expectMinimumCallCount(\$method, \$count, \$msg = '%s') {\n";
  1459. $code .= $this->bailOutIfNotMocked("\$method");
  1460. $code .= " \$this->mock->expectMinimumCallCount(\$method, \$count, \$msg = '%s');\n";
  1461. $code .= " }\n";
  1462. $code .= " function expectNever(\$method) {\n";
  1463. $code .= $this->bailOutIfNotMocked("\$method");
  1464. $code .= " \$this->mock->expectNever(\$method);\n";
  1465. $code .= " }\n";
  1466. $code .= " function expectOnce(\$method, \$args = false, \$msg = '%s') {\n";
  1467. $code .= $this->bailOutIfNotMocked("\$method");
  1468. $code .= " \$this->mock->expectOnce(\$method, \$args, \$msg);\n";
  1469. $code .= " }\n";
  1470. $code .= " function expectAtLeastOnce(\$method, \$args = false, \$msg = '%s') {\n";
  1471. $code .= $this->bailOutIfNotMocked("\$method");
  1472. $code .= " \$this->mock->expectAtLeastOnce(\$method, \$args, \$msg);\n";
  1473. $code .= " }\n";
  1474. return $code;
  1475. }
  1476. /**
  1477. * Adds code for chaining the throw methods.
  1478. * @return string Code for chains.
  1479. * @access private
  1480. */
  1481. protected function chainThrowMethods() {
  1482. $code = " function throwOn(\$method, \$exception = false, \$args = false) {\n";
  1483. $code .= $this->bailOutIfNotMocked("\$method");
  1484. $code .= " \$this->mock->throwOn(\$method, \$exception, \$args);\n";
  1485. $code .= " }\n";
  1486. $code .= " function throwAt(\$timing, \$method, \$exception = false, \$args = false) {\n";
  1487. $code .= $this->bailOutIfNotMocked("\$method");
  1488. $code .= " \$this->mock->throwAt(\$timing, \$method, \$exception, \$args);\n";
  1489. $code .= " }\n";
  1490. $code .= " function errorOn(\$method, \$error = 'A mock error', \$args = false, \$severity = E_USER_ERROR) {\n";
  1491. $code .= $this->bailOutIfNotMocked("\$method");
  1492. $code .= " \$this->mock->errorOn(\$method, \$error, \$args, \$severity);\n";
  1493. $code .= " }\n";
  1494. $code .= " function errorAt(\$timing, \$method, \$error = 'A mock error', \$args = false, \$severity = E_USER_ERROR) {\n";
  1495. $code .= $this->bailOutIfNotMocked("\$method");
  1496. $code .= " \$this->mock->errorAt(\$timing, \$method, \$error, \$args, \$severity);\n";
  1497. $code .= " }\n";
  1498. return $code;
  1499. }
  1500. /**
  1501. * Creates source code to override a list of methods
  1502. * with mock versions.
  1503. * @param array $methods Methods to be overridden
  1504. * with mock versions.
  1505. * @return string Code for overridden chains.
  1506. * @access private
  1507. */
  1508. protected function overrideMethods($methods) {
  1509. $code = "";
  1510. foreach ($methods as $method) {
  1511. if ($this->isConstructor($method)) {
  1512. continue;
  1513. }
  1514. $code .= " " . $this->reflection->getSignature($method) . " {\n";
  1515. $code .= " \$args = func_get_args();\n";
  1516. $code .= " \$result = &\$this->mock->invoke(\"$method\", \$args);\n";
  1517. $code .= " return \$result;\n";
  1518. $code .= " }\n";
  1519. }
  1520. return $code;
  1521. }
  1522. }
  1523. ?>