PageRenderTime 62ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Mockery/Mock.php

http://github.com/padraic/mockery
PHP | 968 lines | 522 code | 120 blank | 326 comment | 72 complexity | 6e2c75227df8f9bf14c2c9648714a771 MD5 | raw file
Possible License(s): BSD-3-Clause
  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 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. use Mockery\HigherOrderMessage;
  22. use Mockery\MockInterface;
  23. use Mockery\LegacyMockInterface;
  24. use Mockery\ExpectsHigherOrderMessage;
  25. use Mockery\Exception\BadMethodCallException;
  26. class Mock implements MockInterface
  27. {
  28. /**
  29. * Stores an array of all expectation directors for this mock
  30. *
  31. * @var array
  32. */
  33. protected $_mockery_expectations = array();
  34. /**
  35. * Stores an initial number of expectations that can be manipulated
  36. * while using the getter method.
  37. *
  38. * @var int
  39. */
  40. protected $_mockery_expectations_count = 0;
  41. /**
  42. * Flag to indicate whether we can ignore method calls missing from our
  43. * expectations
  44. *
  45. * @var bool
  46. */
  47. protected $_mockery_ignoreMissing = false;
  48. /**
  49. * Flag to indicate whether we can defer method calls missing from our
  50. * expectations
  51. *
  52. * @var bool
  53. */
  54. protected $_mockery_deferMissing = false;
  55. /**
  56. * Flag to indicate whether this mock was verified
  57. *
  58. * @var bool
  59. */
  60. protected $_mockery_verified = false;
  61. /**
  62. * Given name of the mock
  63. *
  64. * @var string
  65. */
  66. protected $_mockery_name = null;
  67. /**
  68. * Order number of allocation
  69. *
  70. * @var int
  71. */
  72. protected $_mockery_allocatedOrder = 0;
  73. /**
  74. * Current ordered number
  75. *
  76. * @var int
  77. */
  78. protected $_mockery_currentOrder = 0;
  79. /**
  80. * Ordered groups
  81. *
  82. * @var array
  83. */
  84. protected $_mockery_groups = array();
  85. /**
  86. * Mock container containing this mock object
  87. *
  88. * @var \Mockery\Container
  89. */
  90. protected $_mockery_container = null;
  91. /**
  92. * Instance of a core object on which methods are called in the event
  93. * it has been set, and an expectation for one of the object's methods
  94. * does not exist. This implements a simple partial mock proxy system.
  95. *
  96. * @var object
  97. */
  98. protected $_mockery_partial = null;
  99. /**
  100. * Flag to indicate we should ignore all expectations temporarily. Used
  101. * mainly to prevent expectation matching when in the middle of a mock
  102. * object recording session.
  103. *
  104. * @var bool
  105. */
  106. protected $_mockery_disableExpectationMatching = false;
  107. /**
  108. * Stores all stubbed public methods separate from any on-object public
  109. * properties that may exist.
  110. *
  111. * @var array
  112. */
  113. protected $_mockery_mockableProperties = array();
  114. /**
  115. * @var array
  116. */
  117. protected $_mockery_mockableMethods = array();
  118. /**
  119. * Just a local cache for this mock's target's methods
  120. *
  121. * @var \ReflectionMethod[]
  122. */
  123. protected static $_mockery_methods;
  124. protected $_mockery_allowMockingProtectedMethods = false;
  125. protected $_mockery_receivedMethodCalls;
  126. /**
  127. * If shouldIgnoreMissing is called, this value will be returned on all calls to missing methods
  128. * @var mixed
  129. */
  130. protected $_mockery_defaultReturnValue = null;
  131. /**
  132. * Tracks internally all the bad method call exceptions that happened during runtime
  133. *
  134. * @var array
  135. */
  136. protected $_mockery_thrownExceptions = [];
  137. protected $_mockery_instanceMock = true;
  138. /**
  139. * We want to avoid constructors since class is copied to Generator.php
  140. * for inclusion on extending class definitions.
  141. *
  142. * @param \Mockery\Container $container
  143. * @param object $partialObject
  144. * @param bool $instanceMock
  145. * @return void
  146. */
  147. public function mockery_init(\Mockery\Container $container = null, $partialObject = null, $instanceMock = true)
  148. {
  149. if (is_null($container)) {
  150. $container = new \Mockery\Container();
  151. }
  152. $this->_mockery_container = $container;
  153. if (!is_null($partialObject)) {
  154. $this->_mockery_partial = $partialObject;
  155. }
  156. if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed()) {
  157. foreach ($this->mockery_getMethods() as $method) {
  158. if ($method->isPublic()) {
  159. $this->_mockery_mockableMethods[] = $method->getName();
  160. }
  161. }
  162. }
  163. $this->_mockery_instanceMock = $instanceMock;
  164. }
  165. /**
  166. * Set expected method calls
  167. *
  168. * @param mixed ...$methodNames one or many methods that are expected to be called in this mock
  169. *
  170. * @return \Mockery\ExpectationInterface|\Mockery\Expectation|\Mockery\HigherOrderMessage
  171. */
  172. public function shouldReceive(...$methodNames)
  173. {
  174. if (count($methodNames) === 0) {
  175. return new HigherOrderMessage($this, "shouldReceive");
  176. }
  177. foreach ($methodNames as $method) {
  178. if ("" == $method) {
  179. throw new \InvalidArgumentException("Received empty method name");
  180. }
  181. }
  182. $self = $this;
  183. $allowMockingProtectedMethods = $this->_mockery_allowMockingProtectedMethods;
  184. $lastExpectation = \Mockery::parseShouldReturnArgs(
  185. $this,
  186. $methodNames,
  187. function ($method) use ($self, $allowMockingProtectedMethods) {
  188. $rm = $self->mockery_getMethod($method);
  189. if ($rm) {
  190. if ($rm->isPrivate()) {
  191. throw new \InvalidArgumentException("$method() cannot be mocked as it is a private method");
  192. }
  193. if (!$allowMockingProtectedMethods && $rm->isProtected()) {
  194. throw new \InvalidArgumentException("$method() cannot be mocked as it is a protected method and mocking protected methods is not enabled for the currently used mock object. Use shouldAllowMockingProtectedMethods() to enable mocking of protected methods.");
  195. }
  196. }
  197. $director = $self->mockery_getExpectationsFor($method);
  198. if (!$director) {
  199. $director = new \Mockery\ExpectationDirector($method, $self);
  200. $self->mockery_setExpectationsFor($method, $director);
  201. }
  202. $expectation = new \Mockery\Expectation($self, $method);
  203. $director->addExpectation($expectation);
  204. return $expectation;
  205. }
  206. );
  207. return $lastExpectation;
  208. }
  209. // start method allows
  210. /**
  211. * @param mixed $something String method name or map of method => return
  212. * @return self|\Mockery\ExpectationInterface|\Mockery\Expectation|\Mockery\HigherOrderMessage
  213. */
  214. public function allows($something = [])
  215. {
  216. if (is_string($something)) {
  217. return $this->shouldReceive($something);
  218. }
  219. if (empty($something)) {
  220. return $this->shouldReceive();
  221. }
  222. foreach ($something as $method => $returnValue) {
  223. $this->shouldReceive($method)->andReturn($returnValue);
  224. }
  225. return $this;
  226. }
  227. // end method allows
  228. // start method expects
  229. /**
  230. /**
  231. * @param mixed $something String method name (optional)
  232. * @return \Mockery\ExpectationInterface|\Mockery\Expectation|ExpectsHigherOrderMessage
  233. */
  234. public function expects($something = null)
  235. {
  236. if (is_string($something)) {
  237. return $this->shouldReceive($something)->once();
  238. }
  239. return new ExpectsHigherOrderMessage($this);
  240. }
  241. // end method expects
  242. /**
  243. * Shortcut method for setting an expectation that a method should not be called.
  244. *
  245. * @param array ...$methodNames one or many methods that are expected not to be called in this mock
  246. * @return \Mockery\ExpectationInterface|\Mockery\Expectation|\Mockery\HigherOrderMessage
  247. */
  248. public function shouldNotReceive(...$methodNames)
  249. {
  250. if (count($methodNames) === 0) {
  251. return new HigherOrderMessage($this, "shouldNotReceive");
  252. }
  253. $expectation = call_user_func_array(array($this, 'shouldReceive'), $methodNames);
  254. $expectation->never();
  255. return $expectation;
  256. }
  257. /**
  258. * Allows additional methods to be mocked that do not explicitly exist on mocked class
  259. * @param String $method name of the method to be mocked
  260. * @return Mock
  261. */
  262. public function shouldAllowMockingMethod($method)
  263. {
  264. $this->_mockery_mockableMethods[] = $method;
  265. return $this;
  266. }
  267. /**
  268. * Set mock to ignore unexpected methods and return Undefined class
  269. * @param mixed $returnValue the default return value for calls to missing functions on this mock
  270. * @return Mock
  271. */
  272. public function shouldIgnoreMissing($returnValue = null)
  273. {
  274. $this->_mockery_ignoreMissing = true;
  275. $this->_mockery_defaultReturnValue = $returnValue;
  276. return $this;
  277. }
  278. public function asUndefined()
  279. {
  280. $this->_mockery_ignoreMissing = true;
  281. $this->_mockery_defaultReturnValue = new \Mockery\Undefined();
  282. return $this;
  283. }
  284. /**
  285. * @return Mock
  286. */
  287. public function shouldAllowMockingProtectedMethods()
  288. {
  289. if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed()) {
  290. foreach ($this->mockery_getMethods() as $method) {
  291. if ($method->isProtected()) {
  292. $this->_mockery_mockableMethods[] = $method->getName();
  293. }
  294. }
  295. }
  296. $this->_mockery_allowMockingProtectedMethods = true;
  297. return $this;
  298. }
  299. /**
  300. * Set mock to defer unexpected methods to it's parent
  301. *
  302. * This is particularly useless for this class, as it doesn't have a parent,
  303. * but included for completeness
  304. *
  305. * @deprecated 2.0.0 Please use makePartial() instead
  306. *
  307. * @return Mock
  308. */
  309. public function shouldDeferMissing()
  310. {
  311. return $this->makePartial();
  312. }
  313. /**
  314. * Set mock to defer unexpected methods to it's parent
  315. *
  316. * It was an alias for shouldDeferMissing(), which will be removed
  317. * in 2.0.0.
  318. *
  319. * @return Mock
  320. */
  321. public function makePartial()
  322. {
  323. $this->_mockery_deferMissing = true;
  324. return $this;
  325. }
  326. /**
  327. * In the event shouldReceive() accepting one or more methods/returns,
  328. * this method will switch them from normal expectations to default
  329. * expectations
  330. *
  331. * @return self
  332. */
  333. public function byDefault()
  334. {
  335. foreach ($this->_mockery_expectations as $director) {
  336. $exps = $director->getExpectations();
  337. foreach ($exps as $exp) {
  338. $exp->byDefault();
  339. }
  340. }
  341. return $this;
  342. }
  343. /**
  344. * Capture calls to this mock
  345. */
  346. public function __call($method, array $args)
  347. {
  348. return $this->_mockery_handleMethodCall($method, $args);
  349. }
  350. public static function __callStatic($method, array $args)
  351. {
  352. return self::_mockery_handleStaticMethodCall($method, $args);
  353. }
  354. /**
  355. * Forward calls to this magic method to the __call method
  356. */
  357. public function __toString()
  358. {
  359. return $this->__call('__toString', array());
  360. }
  361. /**
  362. * Iterate across all expectation directors and validate each
  363. *
  364. * @throws \Mockery\CountValidator\Exception
  365. * @return void
  366. */
  367. public function mockery_verify()
  368. {
  369. if ($this->_mockery_verified) {
  370. return;
  371. }
  372. if (isset($this->_mockery_ignoreVerification)
  373. && $this->_mockery_ignoreVerification == true) {
  374. return;
  375. }
  376. $this->_mockery_verified = true;
  377. foreach ($this->_mockery_expectations as $director) {
  378. $director->verify();
  379. }
  380. }
  381. /**
  382. * Gets a list of exceptions thrown by this mock
  383. *
  384. * @return array
  385. */
  386. public function mockery_thrownExceptions()
  387. {
  388. return $this->_mockery_thrownExceptions;
  389. }
  390. /**
  391. * Tear down tasks for this mock
  392. *
  393. * @return void
  394. */
  395. public function mockery_teardown()
  396. {
  397. }
  398. /**
  399. * Fetch the next available allocation order number
  400. *
  401. * @return int
  402. */
  403. public function mockery_allocateOrder()
  404. {
  405. $this->_mockery_allocatedOrder += 1;
  406. return $this->_mockery_allocatedOrder;
  407. }
  408. /**
  409. * Set ordering for a group
  410. *
  411. * @param mixed $group
  412. * @param int $order
  413. */
  414. public function mockery_setGroup($group, $order)
  415. {
  416. $this->_mockery_groups[$group] = $order;
  417. }
  418. /**
  419. * Fetch array of ordered groups
  420. *
  421. * @return array
  422. */
  423. public function mockery_getGroups()
  424. {
  425. return $this->_mockery_groups;
  426. }
  427. /**
  428. * Set current ordered number
  429. *
  430. * @param int $order
  431. */
  432. public function mockery_setCurrentOrder($order)
  433. {
  434. $this->_mockery_currentOrder = $order;
  435. return $this->_mockery_currentOrder;
  436. }
  437. /**
  438. * Get current ordered number
  439. *
  440. * @return int
  441. */
  442. public function mockery_getCurrentOrder()
  443. {
  444. return $this->_mockery_currentOrder;
  445. }
  446. /**
  447. * Validate the current mock's ordering
  448. *
  449. * @param string $method
  450. * @param int $order
  451. * @throws \Mockery\Exception
  452. * @return void
  453. */
  454. public function mockery_validateOrder($method, $order)
  455. {
  456. if ($order < $this->_mockery_currentOrder) {
  457. $exception = new \Mockery\Exception\InvalidOrderException(
  458. 'Method ' . __CLASS__ . '::' . $method . '()'
  459. . ' called out of order: expected order '
  460. . $order . ', was ' . $this->_mockery_currentOrder
  461. );
  462. $exception->setMock($this)
  463. ->setMethodName($method)
  464. ->setExpectedOrder($order)
  465. ->setActualOrder($this->_mockery_currentOrder);
  466. throw $exception;
  467. }
  468. $this->mockery_setCurrentOrder($order);
  469. }
  470. /**
  471. * Gets the count of expectations for this mock
  472. *
  473. * @return int
  474. */
  475. public function mockery_getExpectationCount()
  476. {
  477. $count = $this->_mockery_expectations_count;
  478. foreach ($this->_mockery_expectations as $director) {
  479. $count += $director->getExpectationCount();
  480. }
  481. return $count;
  482. }
  483. /**
  484. * Return the expectations director for the given method
  485. *
  486. * @var string $method
  487. * @return \Mockery\ExpectationDirector|null
  488. */
  489. public function mockery_setExpectationsFor($method, \Mockery\ExpectationDirector $director)
  490. {
  491. $this->_mockery_expectations[$method] = $director;
  492. }
  493. /**
  494. * Return the expectations director for the given method
  495. *
  496. * @var string $method
  497. * @return \Mockery\ExpectationDirector|null
  498. */
  499. public function mockery_getExpectationsFor($method)
  500. {
  501. if (isset($this->_mockery_expectations[$method])) {
  502. return $this->_mockery_expectations[$method];
  503. }
  504. }
  505. /**
  506. * Find an expectation matching the given method and arguments
  507. *
  508. * @var string $method
  509. * @var array $args
  510. * @return \Mockery\Expectation|null
  511. */
  512. public function mockery_findExpectation($method, array $args)
  513. {
  514. if (!isset($this->_mockery_expectations[$method])) {
  515. return null;
  516. }
  517. $director = $this->_mockery_expectations[$method];
  518. return $director->findExpectation($args);
  519. }
  520. /**
  521. * Return the container for this mock
  522. *
  523. * @return \Mockery\Container
  524. */
  525. public function mockery_getContainer()
  526. {
  527. return $this->_mockery_container;
  528. }
  529. /**
  530. * Return the name for this mock
  531. *
  532. * @return string
  533. */
  534. public function mockery_getName()
  535. {
  536. return __CLASS__;
  537. }
  538. /**
  539. * @return array
  540. */
  541. public function mockery_getMockableProperties()
  542. {
  543. return $this->_mockery_mockableProperties;
  544. }
  545. public function __isset($name)
  546. {
  547. if (false === stripos($name, '_mockery_') && method_exists(get_parent_class($this), '__isset')) {
  548. return call_user_func('parent::__isset', $name);
  549. }
  550. return false;
  551. }
  552. public function mockery_getExpectations()
  553. {
  554. return $this->_mockery_expectations;
  555. }
  556. /**
  557. * Calls a parent class method and returns the result. Used in a passthru
  558. * expectation where a real return value is required while still taking
  559. * advantage of expectation matching and call count verification.
  560. *
  561. * @param string $name
  562. * @param array $args
  563. * @return mixed
  564. */
  565. public function mockery_callSubjectMethod($name, array $args)
  566. {
  567. if (!method_exists($this, $name) && method_exists(get_parent_class($this), '__call')) {
  568. return call_user_func('parent::__call', $name, $args);
  569. }
  570. return call_user_func_array('parent::' . $name, $args);
  571. }
  572. /**
  573. * @return string[]
  574. */
  575. public function mockery_getMockableMethods()
  576. {
  577. return $this->_mockery_mockableMethods;
  578. }
  579. /**
  580. * @return bool
  581. */
  582. public function mockery_isAnonymous()
  583. {
  584. $rfc = new \ReflectionClass($this);
  585. // HHVM has a Stringish interface
  586. $interfaces = array_filter($rfc->getInterfaces(), function ($i) {
  587. return $i->getName() !== "Stringish";
  588. });
  589. $onlyImplementsMock = 2 == count($interfaces);
  590. return (false === $rfc->getParentClass()) && $onlyImplementsMock;
  591. }
  592. public function mockery_isInstance()
  593. {
  594. return $this->_mockery_instanceMock;
  595. }
  596. public function __wakeup()
  597. {
  598. /**
  599. * This does not add __wakeup method support. It's a blind method and any
  600. * expected __wakeup work will NOT be performed. It merely cuts off
  601. * annoying errors where a __wakeup exists but is not essential when
  602. * mocking
  603. */
  604. }
  605. public function __destruct()
  606. {
  607. /**
  608. * Overrides real class destructor in case if class was created without original constructor
  609. */
  610. }
  611. public function mockery_getMethod($name)
  612. {
  613. foreach ($this->mockery_getMethods() as $method) {
  614. if ($method->getName() == $name) {
  615. return $method;
  616. }
  617. }
  618. return null;
  619. }
  620. /**
  621. * @param string $name Method name.
  622. *
  623. * @return mixed Generated return value based on the declared return value of the named method.
  624. */
  625. public function mockery_returnValueForMethod($name)
  626. {
  627. if (version_compare(PHP_VERSION, '7.0.0-dev') < 0) {
  628. return;
  629. }
  630. $rm = $this->mockery_getMethod($name);
  631. if (!$rm || !$rm->hasReturnType()) {
  632. return;
  633. }
  634. $returnType = $rm->getReturnType();
  635. // Default return value for methods with nullable type is null
  636. if ($returnType->allowsNull()) {
  637. return null;
  638. }
  639. $type = PHP_VERSION_ID >= 70100 ? $returnType->getName() : (string) $returnType;
  640. switch ($type) {
  641. case '': return;
  642. case 'string': return '';
  643. case 'int': return 0;
  644. case 'float': return 0.0;
  645. case 'bool': return false;
  646. case 'array': return [];
  647. case 'callable':
  648. case 'Closure':
  649. return function () {
  650. };
  651. case 'Traversable':
  652. case 'Generator':
  653. // Remove eval() when minimum version >=5.5
  654. $generator = eval('return function () { yield; };');
  655. return $generator();
  656. case 'self':
  657. return \Mockery::mock($rm->getDeclaringClass()->getName());
  658. case 'void':
  659. return null;
  660. case 'object':
  661. if (version_compare(PHP_VERSION, '7.2.0-dev') >= 0) {
  662. return \Mockery::mock();
  663. }
  664. default:
  665. return \Mockery::mock($type);
  666. }
  667. }
  668. public function shouldHaveReceived($method = null, $args = null)
  669. {
  670. if ($method === null) {
  671. return new HigherOrderMessage($this, "shouldHaveReceived");
  672. }
  673. $expectation = new \Mockery\VerificationExpectation($this, $method);
  674. if (null !== $args) {
  675. $expectation->withArgs($args);
  676. }
  677. $expectation->atLeast()->once();
  678. $director = new \Mockery\VerificationDirector($this->_mockery_getReceivedMethodCalls(), $expectation);
  679. $this->_mockery_expectations_count++;
  680. $director->verify();
  681. return $director;
  682. }
  683. public function shouldHaveBeenCalled()
  684. {
  685. return $this->shouldHaveReceived("__invoke");
  686. }
  687. public function shouldNotHaveReceived($method = null, $args = null)
  688. {
  689. if ($method === null) {
  690. return new HigherOrderMessage($this, "shouldNotHaveReceived");
  691. }
  692. $expectation = new \Mockery\VerificationExpectation($this, $method);
  693. if (null !== $args) {
  694. $expectation->withArgs($args);
  695. }
  696. $expectation->never();
  697. $director = new \Mockery\VerificationDirector($this->_mockery_getReceivedMethodCalls(), $expectation);
  698. $this->_mockery_expectations_count++;
  699. $director->verify();
  700. return null;
  701. }
  702. public function shouldNotHaveBeenCalled(array $args = null)
  703. {
  704. return $this->shouldNotHaveReceived("__invoke", $args);
  705. }
  706. protected static function _mockery_handleStaticMethodCall($method, array $args)
  707. {
  708. $associatedRealObject = \Mockery::fetchMock(__CLASS__);
  709. try {
  710. return $associatedRealObject->__call($method, $args);
  711. } catch (BadMethodCallException $e) {
  712. throw new BadMethodCallException(
  713. 'Static method ' . $associatedRealObject->mockery_getName() . '::' . $method
  714. . '() does not exist on this mock object',
  715. null,
  716. $e
  717. );
  718. }
  719. }
  720. protected function _mockery_getReceivedMethodCalls()
  721. {
  722. return $this->_mockery_receivedMethodCalls ?: $this->_mockery_receivedMethodCalls = new \Mockery\ReceivedMethodCalls();
  723. }
  724. /**
  725. * Called when an instance Mock was created and its constructor is getting called
  726. *
  727. * @see \Mockery\Generator\StringManipulation\Pass\InstanceMockPass
  728. * @param array $args
  729. */
  730. protected function _mockery_constructorCalled(array $args)
  731. {
  732. if (!isset($this->_mockery_expectations['__construct']) /* _mockery_handleMethodCall runs the other checks */) {
  733. return;
  734. }
  735. $this->_mockery_handleMethodCall('__construct', $args);
  736. }
  737. protected function _mockery_findExpectedMethodHandler($method)
  738. {
  739. if (isset($this->_mockery_expectations[$method])) {
  740. return $this->_mockery_expectations[$method];
  741. }
  742. $lowerCasedMockeryExpectations = array_change_key_case($this->_mockery_expectations, CASE_LOWER);
  743. $lowerCasedMethod = strtolower($method);
  744. if (isset($lowerCasedMockeryExpectations[$lowerCasedMethod])) {
  745. return $lowerCasedMockeryExpectations[$lowerCasedMethod];
  746. }
  747. return null;
  748. }
  749. protected function _mockery_handleMethodCall($method, array $args)
  750. {
  751. $this->_mockery_getReceivedMethodCalls()->push(new \Mockery\MethodCall($method, $args));
  752. $rm = $this->mockery_getMethod($method);
  753. if ($rm && $rm->isProtected() && !$this->_mockery_allowMockingProtectedMethods) {
  754. if ($rm->isAbstract()) {
  755. return;
  756. }
  757. try {
  758. $prototype = $rm->getPrototype();
  759. if ($prototype->isAbstract()) {
  760. return;
  761. }
  762. } catch (\ReflectionException $re) {
  763. // noop - there is no hasPrototype method
  764. }
  765. return call_user_func_array("parent::$method", $args);
  766. }
  767. $handler = $this->_mockery_findExpectedMethodHandler($method);
  768. if ($handler !== null && !$this->_mockery_disableExpectationMatching) {
  769. try {
  770. return $handler->call($args);
  771. } catch (\Mockery\Exception\NoMatchingExpectationException $e) {
  772. if (!$this->_mockery_ignoreMissing && !$this->_mockery_deferMissing) {
  773. throw $e;
  774. }
  775. }
  776. }
  777. if (!is_null($this->_mockery_partial) &&
  778. (method_exists($this->_mockery_partial, $method) || method_exists($this->_mockery_partial, '__call'))
  779. ) {
  780. return call_user_func_array(array($this->_mockery_partial, $method), $args);
  781. } elseif ($this->_mockery_deferMissing && is_callable("parent::$method")
  782. && (!$this->hasMethodOverloadingInParentClass() || method_exists(get_parent_class($this), $method))) {
  783. return call_user_func_array("parent::$method", $args);
  784. } elseif ($this->_mockery_deferMissing && method_exists(get_parent_class($this), '__call')) {
  785. return call_user_func('parent::__call', $method, $args);
  786. } elseif ($method == '__toString') {
  787. // __toString is special because we force its addition to the class API regardless of the
  788. // original implementation. Thus, we should always return a string rather than honor
  789. // _mockery_ignoreMissing and break the API with an error.
  790. return sprintf("%s#%s", __CLASS__, spl_object_hash($this));
  791. } elseif ($this->_mockery_ignoreMissing) {
  792. if (\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed() || (method_exists($this->_mockery_partial, $method) || is_callable("parent::$method"))) {
  793. if ($this->_mockery_defaultReturnValue instanceof \Mockery\Undefined) {
  794. return call_user_func_array(array($this->_mockery_defaultReturnValue, $method), $args);
  795. } elseif (null === $this->_mockery_defaultReturnValue) {
  796. return $this->mockery_returnValueForMethod($method);
  797. }
  798. return $this->_mockery_defaultReturnValue;
  799. }
  800. }
  801. $message = 'Method ' . __CLASS__ . '::' . $method .
  802. '() does not exist on this mock object';
  803. if (!is_null($rm)) {
  804. $message = 'Received ' . __CLASS__ .
  805. '::' . $method . '(), but no expectations were specified';
  806. }
  807. $bmce = new BadMethodCallException($message);
  808. $this->_mockery_thrownExceptions[] = $bmce;
  809. throw $bmce;
  810. }
  811. /**
  812. * Uses reflection to get the list of all
  813. * methods within the current mock object
  814. *
  815. * @return array
  816. */
  817. protected function mockery_getMethods()
  818. {
  819. if (static::$_mockery_methods && \Mockery::getConfiguration()->reflectionCacheEnabled()) {
  820. return static::$_mockery_methods;
  821. }
  822. if (isset($this->_mockery_partial)) {
  823. $reflected = new \ReflectionObject($this->_mockery_partial);
  824. } else {
  825. $reflected = new \ReflectionClass($this);
  826. }
  827. return static::$_mockery_methods = $reflected->getMethods();
  828. }
  829. private function hasMethodOverloadingInParentClass()
  830. {
  831. // if there's __call any name would be callable
  832. return is_callable('parent::aFunctionNameThatNoOneWouldEverUseInRealLife12345');
  833. }
  834. /**
  835. * @return array
  836. */
  837. private function getNonPublicMethods()
  838. {
  839. return array_map(
  840. function ($method) {
  841. return $method->getName();
  842. },
  843. array_filter($this->mockery_getMethods(), function ($method) {
  844. return !$method->isPublic();
  845. })
  846. );
  847. }
  848. }