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

/vendor/mockery/mockery/library/Mockery/Expectation.php

https://gitlab.com/Pasantias/pasantiasASLG
PHP | 731 lines | 331 code | 62 blank | 338 comment | 39 complexity | 1a7bc2ae256f5113e3b4238a5f946283 MD5 | raw file
  1. <?php
  2. /**
  3. * Mockery
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://github.com/padraic/mockery/blob/master/LICENSE
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to padraic@php.net so we can send you a copy immediately.
  14. *
  15. * @category Mockery
  16. * @package Mockery
  17. * @copyright Copyright (c) 2010-2014 Pádraic Brady (http://blog.astrumfutura.com)
  18. * @license http://github.com/padraic/mockery/blob/master/LICENSE New BSD License
  19. */
  20. namespace Mockery;
  21. class Expectation implements ExpectationInterface
  22. {
  23. /**
  24. * Mock object to which this expectation belongs
  25. *
  26. * @var object
  27. */
  28. protected $_mock = null;
  29. /**
  30. * Method name
  31. *
  32. * @var string
  33. */
  34. protected $_name = null;
  35. /**
  36. * Arguments expected by this expectation
  37. *
  38. * @var array
  39. */
  40. protected $_expectedArgs = array();
  41. /**
  42. * Count validator store
  43. *
  44. * @var array
  45. */
  46. protected $_countValidators = array();
  47. /**
  48. * The count validator class to use
  49. *
  50. * @var string
  51. */
  52. protected $_countValidatorClass = 'Mockery\CountValidator\Exact';
  53. /**
  54. * Actual count of calls to this expectation
  55. *
  56. * @var int
  57. */
  58. protected $_actualCount = 0;
  59. /**
  60. * Value to return from this expectation
  61. *
  62. * @var mixed
  63. */
  64. protected $_returnValue = null;
  65. /**
  66. * Array of return values as a queue for multiple return sequence
  67. *
  68. * @var array
  69. */
  70. protected $_returnQueue = array();
  71. /**
  72. * Array of closures executed with given arguments to generate a result
  73. * to be returned
  74. *
  75. * @var array
  76. */
  77. protected $_closureQueue = array();
  78. /**
  79. * Array of values to be set when this expectation matches
  80. *
  81. * @var array
  82. */
  83. protected $_setQueue = array();
  84. /**
  85. * Integer representing the call order of this expectation
  86. *
  87. * @var int
  88. */
  89. protected $_orderNumber = null;
  90. /**
  91. * Integer representing the call order of this expectation on a global basis
  92. *
  93. * @var int
  94. */
  95. protected $_globalOrderNumber = null;
  96. /**
  97. * Flag indicating that an exception is expected to be throw (not returned)
  98. *
  99. * @var bool
  100. */
  101. protected $_throw = false;
  102. /**
  103. * Flag indicating whether the order of calling is determined locally or
  104. * globally
  105. *
  106. * @var bool
  107. */
  108. protected $_globally = false;
  109. /**
  110. * Flag indicating we expect no arguments
  111. *
  112. * @var bool
  113. */
  114. protected $_noArgsExpectation = false;
  115. /**
  116. * Flag indicating if the return value should be obtained from the original
  117. * class method instead of returning predefined values from the return queue
  118. *
  119. * @var bool
  120. */
  121. protected $_passthru = false;
  122. /**
  123. * Constructor
  124. *
  125. * @param \Mockery\MockInterface $mock
  126. * @param string $name
  127. */
  128. public function __construct(\Mockery\MockInterface $mock, $name)
  129. {
  130. $this->_mock = $mock;
  131. $this->_name = $name;
  132. }
  133. /**
  134. * Return a string with the method name and arguments formatted
  135. *
  136. * @param string $name Name of the expected method
  137. * @param array $args List of arguments to the method
  138. * @return string
  139. */
  140. public function __toString()
  141. {
  142. return \Mockery::formatArgs($this->_name, $this->_expectedArgs);
  143. }
  144. /**
  145. * Verify the current call, i.e. that the given arguments match those
  146. * of this expectation
  147. *
  148. * @param array $args
  149. * @return mixed
  150. */
  151. public function verifyCall(array $args)
  152. {
  153. $this->validateOrder();
  154. $this->_actualCount++;
  155. if (true === $this->_passthru) {
  156. return $this->_mock->mockery_callSubjectMethod($this->_name, $args);
  157. }
  158. $return = $this->_getReturnValue($args);
  159. if ($return instanceof \Exception && $this->_throw === true) {
  160. throw $return;
  161. }
  162. $this->_setValues();
  163. return $return;
  164. }
  165. /**
  166. * Sets public properties with queued values to the mock object
  167. *
  168. * @param array $args
  169. * @return mixed
  170. */
  171. protected function _setValues()
  172. {
  173. foreach ($this->_setQueue as $name => &$values) {
  174. if (count($values) > 0) {
  175. $value = array_shift($values);
  176. $this->_mock->{$name} = $value;
  177. }
  178. }
  179. }
  180. /**
  181. * Fetch the return value for the matching args
  182. *
  183. * @param array $args
  184. * @return mixed
  185. */
  186. protected function _getReturnValue(array $args)
  187. {
  188. if (count($this->_closureQueue) > 1) {
  189. return call_user_func_array(array_shift($this->_closureQueue), $args);
  190. } elseif (count($this->_closureQueue) > 0) {
  191. return call_user_func_array(current($this->_closureQueue), $args);
  192. } elseif (count($this->_returnQueue) > 1) {
  193. return array_shift($this->_returnQueue);
  194. } elseif (count($this->_returnQueue) > 0) {
  195. return current($this->_returnQueue);
  196. }
  197. }
  198. /**
  199. * Checks if this expectation is eligible for additional calls
  200. *
  201. * @return bool
  202. */
  203. public function isEligible()
  204. {
  205. foreach ($this->_countValidators as $validator) {
  206. if (!$validator->isEligible($this->_actualCount)) {
  207. return false;
  208. }
  209. }
  210. return true;
  211. }
  212. /**
  213. * Check if there is a constraint on call count
  214. *
  215. * @return bool
  216. */
  217. public function isCallCountConstrained()
  218. {
  219. return (count($this->_countValidators) > 0);
  220. }
  221. /**
  222. * Verify call order
  223. *
  224. * @return void
  225. */
  226. public function validateOrder()
  227. {
  228. if ($this->_orderNumber) {
  229. $this->_mock->mockery_validateOrder((string) $this, $this->_orderNumber, $this->_mock);
  230. }
  231. if ($this->_globalOrderNumber) {
  232. $this->_mock->mockery_getContainer()
  233. ->mockery_validateOrder((string) $this, $this->_globalOrderNumber, $this->_mock);
  234. }
  235. }
  236. /**
  237. * Verify this expectation
  238. *
  239. * @return bool
  240. */
  241. public function verify()
  242. {
  243. foreach ($this->_countValidators as $validator) {
  244. $validator->validate($this->_actualCount);
  245. }
  246. }
  247. /**
  248. * Check if passed arguments match an argument expectation
  249. *
  250. * @param array $args
  251. * @return bool
  252. */
  253. public function matchArgs(array $args)
  254. {
  255. if (empty($this->_expectedArgs) && !$this->_noArgsExpectation) {
  256. return true;
  257. }
  258. if (count($args) !== count($this->_expectedArgs)) {
  259. return false;
  260. }
  261. $argCount = count($args);
  262. for ($i=0; $i<$argCount; $i++) {
  263. $param =& $args[$i];
  264. if (!$this->_matchArg($this->_expectedArgs[$i], $param)) {
  265. return false;
  266. }
  267. }
  268. return true;
  269. }
  270. /**
  271. * Check if passed argument matches an argument expectation
  272. *
  273. * @param array $args
  274. * @return bool
  275. */
  276. protected function _matchArg($expected, &$actual)
  277. {
  278. if ($expected === $actual) {
  279. return true;
  280. }
  281. if (!is_object($expected) && !is_object($actual) && $expected == $actual) {
  282. return true;
  283. }
  284. if (is_string($expected) && !is_array($actual) && !is_object($actual)) {
  285. # push/pop an error handler here to to make sure no error/exception thrown if $expected is not a regex
  286. set_error_handler(function () {});
  287. $result = preg_match($expected, (string) $actual);
  288. restore_error_handler();
  289. if ($result) {
  290. return true;
  291. }
  292. }
  293. if (is_string($expected) && is_object($actual)) {
  294. $result = $actual instanceof $expected;
  295. if ($result) {
  296. return true;
  297. }
  298. }
  299. if ($expected instanceof \Mockery\Matcher\MatcherAbstract) {
  300. return $expected->match($actual);
  301. }
  302. if (is_a($expected, '\Hamcrest\Matcher') || is_a($expected, '\Hamcrest_Matcher')) {
  303. return $expected->matches($actual);
  304. }
  305. return false;
  306. }
  307. /**
  308. * Expected argument setter for the expectation
  309. *
  310. * @param mixed ...
  311. * @return self
  312. */
  313. public function with()
  314. {
  315. return $this->withArgs(func_get_args());
  316. }
  317. /**
  318. * Expected arguments for the expectation passed as an array
  319. *
  320. * @param array $args
  321. * @return self
  322. */
  323. public function withArgs(array $args)
  324. {
  325. if (empty($args)) {
  326. return $this->withNoArgs();
  327. }
  328. $this->_expectedArgs = $args;
  329. $this->_noArgsExpectation = false;
  330. return $this;
  331. }
  332. /**
  333. * Set with() as no arguments expected
  334. *
  335. * @return self
  336. */
  337. public function withNoArgs()
  338. {
  339. $this->_noArgsExpectation = true;
  340. $this->_expectedArgs = null;
  341. return $this;
  342. }
  343. /**
  344. * Set expectation that any arguments are acceptable
  345. *
  346. * @return self
  347. */
  348. public function withAnyArgs()
  349. {
  350. $this->_expectedArgs = array();
  351. return $this;
  352. }
  353. /**
  354. * Set a return value, or sequential queue of return values
  355. *
  356. * @param mixed ...
  357. * @return self
  358. */
  359. public function andReturn()
  360. {
  361. $this->_returnQueue = func_get_args();
  362. return $this;
  363. }
  364. /**
  365. * Return this mock, like a fluent interface
  366. *
  367. * @return self
  368. */
  369. public function andReturnSelf()
  370. {
  371. return $this->andReturn($this->_mock);
  372. }
  373. /**
  374. * Set a sequential queue of return values with an array
  375. *
  376. * @param array $values
  377. * @return self
  378. */
  379. public function andReturnValues(array $values)
  380. {
  381. call_user_func_array(array($this, 'andReturn'), $values);
  382. return $this;
  383. }
  384. /**
  385. * Set a closure or sequence of closures with which to generate return
  386. * values. The arguments passed to the expected method are passed to the
  387. * closures as parameters.
  388. *
  389. * @param callable ...
  390. * @return self
  391. */
  392. public function andReturnUsing()
  393. {
  394. $this->_closureQueue = func_get_args();
  395. return $this;
  396. }
  397. /**
  398. * Return a self-returning black hole object.
  399. *
  400. * @return self
  401. */
  402. public function andReturnUndefined()
  403. {
  404. $this->andReturn(new \Mockery\Undefined);
  405. return $this;
  406. }
  407. /**
  408. * Return null. This is merely a language construct for Mock describing.
  409. *
  410. * @return self
  411. */
  412. public function andReturnNull()
  413. {
  414. return $this;
  415. }
  416. /**
  417. * Set Exception class and arguments to that class to be thrown
  418. *
  419. * @param string $exception
  420. * @param string $message
  421. * @param int $code
  422. * @param Exception $previous
  423. * @return self
  424. */
  425. public function andThrow($exception, $message = '', $code = 0, \Exception $previous = null)
  426. {
  427. $this->_throw = true;
  428. if (is_object($exception)) {
  429. $this->andReturn($exception);
  430. } else {
  431. $this->andReturn(new $exception($message, $code, $previous));
  432. }
  433. return $this;
  434. }
  435. /**
  436. * Set Exception classes to be thrown
  437. *
  438. * @param array $exceptions
  439. * @return self
  440. */
  441. public function andThrowExceptions(array $exceptions)
  442. {
  443. $this->_throw = true;
  444. foreach ($exceptions as $exception) {
  445. if (!is_object($exception)) {
  446. throw new Exception('You must pass an array of exception objects to andThrowExceptions');
  447. }
  448. }
  449. return $this->andReturnValues($exceptions);
  450. }
  451. /**
  452. * Register values to be set to a public property each time this expectation occurs
  453. *
  454. * @param string $name
  455. * @param mixed $value
  456. * @return self
  457. */
  458. public function andSet($name, $value)
  459. {
  460. $values = func_get_args();
  461. array_shift($values);
  462. $this->_setQueue[$name] = $values;
  463. return $this;
  464. }
  465. /**
  466. * Alias to andSet(). Allows the natural English construct
  467. * - set('foo', 'bar')->andReturn('bar')
  468. *
  469. * @param string $name
  470. * @param mixed $value
  471. * @return self
  472. */
  473. public function set($name, $value)
  474. {
  475. return call_user_func_array(array($this, 'andSet'), func_get_args());
  476. }
  477. /**
  478. * Indicates this expectation should occur zero or more times
  479. *
  480. * @return self
  481. */
  482. public function zeroOrMoreTimes()
  483. {
  484. $this->atLeast()->never();
  485. }
  486. /**
  487. * Indicates the number of times this expectation should occur
  488. *
  489. * @param int $limit
  490. * @return self
  491. */
  492. public function times($limit = null)
  493. {
  494. if (is_null($limit)) {
  495. return $this;
  496. }
  497. $this->_countValidators[] = new $this->_countValidatorClass($this, $limit);
  498. $this->_countValidatorClass = 'Mockery\CountValidator\Exact';
  499. return $this;
  500. }
  501. /**
  502. * Indicates that this expectation is never expected to be called
  503. *
  504. * @return self
  505. */
  506. public function never()
  507. {
  508. return $this->times(0);
  509. }
  510. /**
  511. * Indicates that this expectation is expected exactly once
  512. *
  513. * @return self
  514. */
  515. public function once()
  516. {
  517. return $this->times(1);
  518. }
  519. /**
  520. * Indicates that this expectation is expected exactly twice
  521. *
  522. * @return self
  523. */
  524. public function twice()
  525. {
  526. return $this->times(2);
  527. }
  528. /**
  529. * Sets next count validator to the AtLeast instance
  530. *
  531. * @return self
  532. */
  533. public function atLeast()
  534. {
  535. $this->_countValidatorClass = 'Mockery\CountValidator\AtLeast';
  536. return $this;
  537. }
  538. /**
  539. * Sets next count validator to the AtMost instance
  540. *
  541. * @return self
  542. */
  543. public function atMost()
  544. {
  545. $this->_countValidatorClass = 'Mockery\CountValidator\AtMost';
  546. return $this;
  547. }
  548. /**
  549. * Shorthand for setting minimum and maximum constraints on call counts
  550. *
  551. * @param int $minimum
  552. * @param int $maximum
  553. */
  554. public function between($minimum, $maximum)
  555. {
  556. return $this->atLeast()->times($minimum)->atMost()->times($maximum);
  557. }
  558. /**
  559. * Indicates that this expectation must be called in a specific given order
  560. *
  561. * @param string $group Name of the ordered group
  562. * @return self
  563. */
  564. public function ordered($group = null)
  565. {
  566. if ($this->_globally) {
  567. $this->_globalOrderNumber = $this->_defineOrdered($group, $this->_mock->mockery_getContainer());
  568. } else {
  569. $this->_orderNumber = $this->_defineOrdered($group, $this->_mock);
  570. }
  571. $this->_globally = false;
  572. return $this;
  573. }
  574. /**
  575. * Indicates call order should apply globally
  576. *
  577. * @return self
  578. */
  579. public function globally()
  580. {
  581. $this->_globally = true;
  582. return $this;
  583. }
  584. /**
  585. * Setup the ordering tracking on the mock or mock container
  586. *
  587. * @param string $group
  588. * @param object $ordering
  589. * @return int
  590. */
  591. protected function _defineOrdered($group, $ordering)
  592. {
  593. $groups = $ordering->mockery_getGroups();
  594. if (is_null($group)) {
  595. $result = $ordering->mockery_allocateOrder();
  596. } elseif (isset($groups[$group])) {
  597. $result = $groups[$group];
  598. } else {
  599. $result = $ordering->mockery_allocateOrder();
  600. $ordering->mockery_setGroup($group, $result);
  601. }
  602. return $result;
  603. }
  604. /**
  605. * Return order number
  606. *
  607. * @return int
  608. */
  609. public function getOrderNumber()
  610. {
  611. return $this->_orderNumber;
  612. }
  613. /**
  614. * Mark this expectation as being a default
  615. *
  616. * @return self
  617. */
  618. public function byDefault()
  619. {
  620. $director = $this->_mock->mockery_getExpectationsFor($this->_name);
  621. if (!empty($director)) {
  622. $director->makeExpectationDefault($this);
  623. }
  624. return $this;
  625. }
  626. /**
  627. * Return the parent mock of the expectation
  628. *
  629. * @return \Mockery\MockInterface
  630. */
  631. public function getMock()
  632. {
  633. return $this->_mock;
  634. }
  635. /**
  636. * Flag this expectation as calling the original class method with the
  637. * any provided arguments instead of using a return value queue.
  638. *
  639. * @return self
  640. */
  641. public function passthru()
  642. {
  643. if ($this->_mock instanceof Mock) {
  644. throw new Exception(
  645. 'Mock Objects not created from a loaded/existing class are '
  646. . 'incapable of passing method calls through to a parent class'
  647. );
  648. }
  649. $this->_passthru = true;
  650. return $this;
  651. }
  652. /**
  653. * Cloning logic
  654. *
  655. */
  656. public function __clone()
  657. {
  658. $newValidators = array();
  659. $countValidators = $this->_countValidators;
  660. foreach ($countValidators as $validator) {
  661. $newValidators[] = clone $validator;
  662. }
  663. $this->_countValidators = $newValidators;
  664. }
  665. public function getName()
  666. {
  667. return $this->_name;
  668. }
  669. }