PageRenderTime 49ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://gitlab.com/ealexis.t/trends
PHP | 757 lines | 352 code | 66 blank | 339 comment | 43 complexity | 4d488931882f870fbdfe982cd2b7c898 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. $rm = $this->_mock->mockery_getMethod($this->_name);
  198. if ($rm && version_compare(PHP_VERSION, '7.0.0-dev') >= 0 && $rm->hasReturnType()) {
  199. $type = (string) $rm->getReturnType();
  200. switch ($type) {
  201. case '': return;
  202. case 'string': return '';
  203. case 'int': return 0;
  204. case 'float': return 0.0;
  205. case 'bool': return false;
  206. case 'array': return array();
  207. case 'callable':
  208. case 'Closure':
  209. return function () {};
  210. case 'Traversable':
  211. case 'Generator':
  212. // Remove eval() when minimum version >=5.5
  213. $generator = eval('return function () { yield; };');
  214. return $generator();
  215. default:
  216. return \Mockery::mock($type);
  217. }
  218. }
  219. }
  220. /**
  221. * Checks if this expectation is eligible for additional calls
  222. *
  223. * @return bool
  224. */
  225. public function isEligible()
  226. {
  227. foreach ($this->_countValidators as $validator) {
  228. if (!$validator->isEligible($this->_actualCount)) {
  229. return false;
  230. }
  231. }
  232. return true;
  233. }
  234. /**
  235. * Check if there is a constraint on call count
  236. *
  237. * @return bool
  238. */
  239. public function isCallCountConstrained()
  240. {
  241. return (count($this->_countValidators) > 0);
  242. }
  243. /**
  244. * Verify call order
  245. *
  246. * @return void
  247. */
  248. public function validateOrder()
  249. {
  250. if ($this->_orderNumber) {
  251. $this->_mock->mockery_validateOrder((string) $this, $this->_orderNumber, $this->_mock);
  252. }
  253. if ($this->_globalOrderNumber) {
  254. $this->_mock->mockery_getContainer()
  255. ->mockery_validateOrder((string) $this, $this->_globalOrderNumber, $this->_mock);
  256. }
  257. }
  258. /**
  259. * Verify this expectation
  260. *
  261. * @return bool
  262. */
  263. public function verify()
  264. {
  265. foreach ($this->_countValidators as $validator) {
  266. $validator->validate($this->_actualCount);
  267. }
  268. }
  269. /**
  270. * Check if passed arguments match an argument expectation
  271. *
  272. * @param array $args
  273. * @return bool
  274. */
  275. public function matchArgs(array $args)
  276. {
  277. if (empty($this->_expectedArgs) && !$this->_noArgsExpectation) {
  278. return true;
  279. }
  280. if (count($args) !== count($this->_expectedArgs)) {
  281. return false;
  282. }
  283. $argCount = count($args);
  284. for ($i=0; $i<$argCount; $i++) {
  285. $param =& $args[$i];
  286. if (!$this->_matchArg($this->_expectedArgs[$i], $param)) {
  287. return false;
  288. }
  289. }
  290. return true;
  291. }
  292. /**
  293. * Check if passed argument matches an argument expectation
  294. *
  295. * @param array $args
  296. * @return bool
  297. */
  298. protected function _matchArg($expected, &$actual)
  299. {
  300. if ($expected === $actual) {
  301. return true;
  302. }
  303. if (!is_object($expected) && !is_object($actual) && $expected == $actual) {
  304. return true;
  305. }
  306. if (is_string($expected) && !is_array($actual) && !is_object($actual)) {
  307. # push/pop an error handler here to to make sure no error/exception thrown if $expected is not a regex
  308. set_error_handler(function () {});
  309. $result = preg_match($expected, (string) $actual);
  310. restore_error_handler();
  311. if ($result) {
  312. return true;
  313. }
  314. }
  315. if (is_string($expected) && is_object($actual)) {
  316. $result = $actual instanceof $expected;
  317. if ($result) {
  318. return true;
  319. }
  320. }
  321. if ($expected instanceof \Mockery\Matcher\MatcherAbstract) {
  322. return $expected->match($actual);
  323. }
  324. if (is_a($expected, '\Hamcrest\Matcher') || is_a($expected, '\Hamcrest_Matcher')) {
  325. return $expected->matches($actual);
  326. }
  327. return false;
  328. }
  329. /**
  330. * Expected argument setter for the expectation
  331. *
  332. * @param mixed ...
  333. * @return self
  334. */
  335. public function with()
  336. {
  337. return $this->withArgs(func_get_args());
  338. }
  339. /**
  340. * Expected arguments for the expectation passed as an array
  341. *
  342. * @param array $args
  343. * @return self
  344. */
  345. public function withArgs(array $args)
  346. {
  347. if (empty($args)) {
  348. return $this->withNoArgs();
  349. }
  350. $this->_expectedArgs = $args;
  351. $this->_noArgsExpectation = false;
  352. return $this;
  353. }
  354. /**
  355. * Set with() as no arguments expected
  356. *
  357. * @return self
  358. */
  359. public function withNoArgs()
  360. {
  361. $this->_noArgsExpectation = true;
  362. $this->_expectedArgs = null;
  363. return $this;
  364. }
  365. /**
  366. * Set expectation that any arguments are acceptable
  367. *
  368. * @return self
  369. */
  370. public function withAnyArgs()
  371. {
  372. $this->_expectedArgs = array();
  373. return $this;
  374. }
  375. /**
  376. * Set a return value, or sequential queue of return values
  377. *
  378. * @param mixed ...
  379. * @return self
  380. */
  381. public function andReturn()
  382. {
  383. $this->_returnQueue = func_get_args();
  384. return $this;
  385. }
  386. /**
  387. * Return this mock, like a fluent interface
  388. *
  389. * @return self
  390. */
  391. public function andReturnSelf()
  392. {
  393. return $this->andReturn($this->_mock);
  394. }
  395. /**
  396. * Set a sequential queue of return values with an array
  397. *
  398. * @param array $values
  399. * @return self
  400. */
  401. public function andReturnValues(array $values)
  402. {
  403. call_user_func_array(array($this, 'andReturn'), $values);
  404. return $this;
  405. }
  406. /**
  407. * Set a closure or sequence of closures with which to generate return
  408. * values. The arguments passed to the expected method are passed to the
  409. * closures as parameters.
  410. *
  411. * @param callable ...
  412. * @return self
  413. */
  414. public function andReturnUsing()
  415. {
  416. $this->_closureQueue = func_get_args();
  417. return $this;
  418. }
  419. /**
  420. * Return a self-returning black hole object.
  421. *
  422. * @return self
  423. */
  424. public function andReturnUndefined()
  425. {
  426. $this->andReturn(new \Mockery\Undefined);
  427. return $this;
  428. }
  429. /**
  430. * Return null. This is merely a language construct for Mock describing.
  431. *
  432. * @return self
  433. */
  434. public function andReturnNull()
  435. {
  436. return $this;
  437. }
  438. /**
  439. * Set Exception class and arguments to that class to be thrown
  440. *
  441. * @param string $exception
  442. * @param string $message
  443. * @param int $code
  444. * @param Exception $previous
  445. * @return self
  446. */
  447. public function andThrow($exception, $message = '', $code = 0, \Exception $previous = null)
  448. {
  449. $this->_throw = true;
  450. if (is_object($exception)) {
  451. $this->andReturn($exception);
  452. } else {
  453. $this->andReturn(new $exception($message, $code, $previous));
  454. }
  455. return $this;
  456. }
  457. /**
  458. * Set Exception classes to be thrown
  459. *
  460. * @param array $exceptions
  461. * @return self
  462. */
  463. public function andThrowExceptions(array $exceptions)
  464. {
  465. $this->_throw = true;
  466. foreach ($exceptions as $exception) {
  467. if (!is_object($exception)) {
  468. throw new Exception('You must pass an array of exception objects to andThrowExceptions');
  469. }
  470. }
  471. return $this->andReturnValues($exceptions);
  472. }
  473. /**
  474. * Register values to be set to a public property each time this expectation occurs
  475. *
  476. * @param string $name
  477. * @param mixed $value
  478. * @return self
  479. */
  480. public function andSet($name, $value)
  481. {
  482. $values = func_get_args();
  483. array_shift($values);
  484. $this->_setQueue[$name] = $values;
  485. return $this;
  486. }
  487. /**
  488. * Alias to andSet(). Allows the natural English construct
  489. * - set('foo', 'bar')->andReturn('bar')
  490. *
  491. * @param string $name
  492. * @param mixed $value
  493. * @return self
  494. */
  495. public function set($name, $value)
  496. {
  497. return call_user_func_array(array($this, 'andSet'), func_get_args());
  498. }
  499. /**
  500. * Indicates this expectation should occur zero or more times
  501. *
  502. * @return self
  503. */
  504. public function zeroOrMoreTimes()
  505. {
  506. $this->atLeast()->never();
  507. }
  508. /**
  509. * Indicates the number of times this expectation should occur
  510. *
  511. * @param int $limit
  512. * @return self
  513. */
  514. public function times($limit = null)
  515. {
  516. if (is_null($limit)) {
  517. return $this;
  518. }
  519. $this->_countValidators[] = new $this->_countValidatorClass($this, $limit);
  520. $this->_countValidatorClass = 'Mockery\CountValidator\Exact';
  521. return $this;
  522. }
  523. /**
  524. * Indicates that this expectation is never expected to be called
  525. *
  526. * @return self
  527. */
  528. public function never()
  529. {
  530. return $this->times(0);
  531. }
  532. /**
  533. * Indicates that this expectation is expected exactly once
  534. *
  535. * @return self
  536. */
  537. public function once()
  538. {
  539. return $this->times(1);
  540. }
  541. /**
  542. * Indicates that this expectation is expected exactly twice
  543. *
  544. * @return self
  545. */
  546. public function twice()
  547. {
  548. return $this->times(2);
  549. }
  550. /**
  551. * Sets next count validator to the AtLeast instance
  552. *
  553. * @return self
  554. */
  555. public function atLeast()
  556. {
  557. $this->_countValidatorClass = 'Mockery\CountValidator\AtLeast';
  558. return $this;
  559. }
  560. /**
  561. * Sets next count validator to the AtMost instance
  562. *
  563. * @return self
  564. */
  565. public function atMost()
  566. {
  567. $this->_countValidatorClass = 'Mockery\CountValidator\AtMost';
  568. return $this;
  569. }
  570. /**
  571. * Shorthand for setting minimum and maximum constraints on call counts
  572. *
  573. * @param int $minimum
  574. * @param int $maximum
  575. */
  576. public function between($minimum, $maximum)
  577. {
  578. return $this->atLeast()->times($minimum)->atMost()->times($maximum);
  579. }
  580. /**
  581. * Indicates that this expectation must be called in a specific given order
  582. *
  583. * @param string $group Name of the ordered group
  584. * @return self
  585. */
  586. public function ordered($group = null)
  587. {
  588. if ($this->_globally) {
  589. $this->_globalOrderNumber = $this->_defineOrdered($group, $this->_mock->mockery_getContainer());
  590. } else {
  591. $this->_orderNumber = $this->_defineOrdered($group, $this->_mock);
  592. }
  593. $this->_globally = false;
  594. return $this;
  595. }
  596. /**
  597. * Indicates call order should apply globally
  598. *
  599. * @return self
  600. */
  601. public function globally()
  602. {
  603. $this->_globally = true;
  604. return $this;
  605. }
  606. /**
  607. * Setup the ordering tracking on the mock or mock container
  608. *
  609. * @param string $group
  610. * @param object $ordering
  611. * @return int
  612. */
  613. protected function _defineOrdered($group, $ordering)
  614. {
  615. $groups = $ordering->mockery_getGroups();
  616. if (is_null($group)) {
  617. $result = $ordering->mockery_allocateOrder();
  618. } elseif (isset($groups[$group])) {
  619. $result = $groups[$group];
  620. } else {
  621. $result = $ordering->mockery_allocateOrder();
  622. $ordering->mockery_setGroup($group, $result);
  623. }
  624. return $result;
  625. }
  626. /**
  627. * Return order number
  628. *
  629. * @return int
  630. */
  631. public function getOrderNumber()
  632. {
  633. return $this->_orderNumber;
  634. }
  635. /**
  636. * Mark this expectation as being a default
  637. *
  638. * @return self
  639. */
  640. public function byDefault()
  641. {
  642. $director = $this->_mock->mockery_getExpectationsFor($this->_name);
  643. if (!empty($director)) {
  644. $director->makeExpectationDefault($this);
  645. }
  646. return $this;
  647. }
  648. /**
  649. * Return the parent mock of the expectation
  650. *
  651. * @return \Mockery\MockInterface
  652. */
  653. public function getMock()
  654. {
  655. return $this->_mock;
  656. }
  657. /**
  658. * Flag this expectation as calling the original class method with the
  659. * any provided arguments instead of using a return value queue.
  660. *
  661. * @return self
  662. */
  663. public function passthru()
  664. {
  665. if ($this->_mock instanceof Mock) {
  666. throw new Exception(
  667. 'Mock Objects not created from a loaded/existing class are '
  668. . 'incapable of passing method calls through to a parent class'
  669. );
  670. }
  671. $this->_passthru = true;
  672. return $this;
  673. }
  674. /**
  675. * Cloning logic
  676. *
  677. */
  678. public function __clone()
  679. {
  680. $newValidators = array();
  681. $countValidators = $this->_countValidators;
  682. foreach ($countValidators as $validator) {
  683. $newValidators[] = clone $validator;
  684. }
  685. $this->_countValidators = $newValidators;
  686. }
  687. public function getName()
  688. {
  689. return $this->_name;
  690. }
  691. }