4 * This file is part of the Prophecy.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
6 * Marcello Duarte <marcello.duarte@gmail.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Prophecy\Prophecy;
14 use Prophecy\Argument;
17 use Prophecy\Prediction;
18 use Prophecy\Exception\Doubler\MethodNotFoundException;
19 use Prophecy\Exception\InvalidArgumentException;
20 use Prophecy\Exception\Prophecy\MethodProphecyException;
25 * @author Konstantin Kudryashov <ever.zet@gmail.com>
29 private $objectProphecy;
31 private $argumentsWildcard;
34 private $checkedPredictions = array();
35 private $bound = false;
36 private $voidReturnType = false;
39 * Initializes method prophecy.
41 * @param ObjectProphecy $objectProphecy
42 * @param string $methodName
43 * @param null|Argument\ArgumentsWildcard|array $arguments
45 * @throws \Prophecy\Exception\Doubler\MethodNotFoundException If method not found
47 public function __construct(ObjectProphecy $objectProphecy, $methodName, $arguments = null)
49 $double = $objectProphecy->reveal();
50 if (!method_exists($double, $methodName)) {
51 throw new MethodNotFoundException(sprintf(
52 'Method `%s::%s()` is not defined.', get_class($double), $methodName
53 ), get_class($double), $methodName, $arguments);
56 $this->objectProphecy = $objectProphecy;
57 $this->methodName = $methodName;
59 $reflectedMethod = new \ReflectionMethod($double, $methodName);
60 if ($reflectedMethod->isFinal()) {
61 throw new MethodProphecyException(sprintf(
62 "Can not add prophecy for a method `%s::%s()`\n".
63 "as it is a final method.",
69 if (null !== $arguments) {
70 $this->withArguments($arguments);
73 if (version_compare(PHP_VERSION, '7.0', '>=') && true === $reflectedMethod->hasReturnType()) {
74 $type = (string) $reflectedMethod->getReturnType();
76 if ('void' === $type) {
77 $this->voidReturnType = true;
81 $this->will(function () use ($type) {
83 case 'string': return '';
84 case 'float': return 0.0;
86 case 'bool': return false;
87 case 'array': return array();
91 return function () {};
95 // Remove eval() when minimum version >=5.5
96 /** @var callable $generator */
97 $generator = eval('return function () { yield; };');
101 $prophet = new Prophet;
102 return $prophet->prophesize($type)->reveal();
109 * Sets argument wildcard.
111 * @param array|Argument\ArgumentsWildcard $arguments
115 * @throws \Prophecy\Exception\InvalidArgumentException
117 public function withArguments($arguments)
119 if (is_array($arguments)) {
120 $arguments = new Argument\ArgumentsWildcard($arguments);
123 if (!$arguments instanceof Argument\ArgumentsWildcard) {
124 throw new InvalidArgumentException(sprintf(
125 "Either an array or an instance of ArgumentsWildcard expected as\n".
126 'a `MethodProphecy::withArguments()` argument, but got %s.',
131 $this->argumentsWildcard = $arguments;
137 * Sets custom promise to the prophecy.
139 * @param callable|Promise\PromiseInterface $promise
143 * @throws \Prophecy\Exception\InvalidArgumentException
145 public function will($promise)
147 if (is_callable($promise)) {
148 $promise = new Promise\CallbackPromise($promise);
151 if (!$promise instanceof Promise\PromiseInterface) {
152 throw new InvalidArgumentException(sprintf(
153 'Expected callable or instance of PromiseInterface, but got %s.',
158 $this->bindToObjectProphecy();
159 $this->promise = $promise;
165 * Sets return promise to the prophecy.
167 * @see Prophecy\Promise\ReturnPromise
171 public function willReturn()
173 if ($this->voidReturnType) {
174 throw new MethodProphecyException(
175 "The method \"$this->methodName\" has a void return type, and so cannot return anything",
180 return $this->will(new Promise\ReturnPromise(func_get_args()));
184 * Sets return argument promise to the prophecy.
186 * @param int $index The zero-indexed number of the argument to return
188 * @see Prophecy\Promise\ReturnArgumentPromise
192 public function willReturnArgument($index = 0)
194 if ($this->voidReturnType) {
195 throw new MethodProphecyException("The method \"$this->methodName\" has a void return type", $this);
198 return $this->will(new Promise\ReturnArgumentPromise($index));
202 * Sets throw promise to the prophecy.
204 * @see Prophecy\Promise\ThrowPromise
206 * @param string|\Exception $exception Exception class or instance
210 public function willThrow($exception)
212 return $this->will(new Promise\ThrowPromise($exception));
216 * Sets custom prediction to the prophecy.
218 * @param callable|Prediction\PredictionInterface $prediction
222 * @throws \Prophecy\Exception\InvalidArgumentException
224 public function should($prediction)
226 if (is_callable($prediction)) {
227 $prediction = new Prediction\CallbackPrediction($prediction);
230 if (!$prediction instanceof Prediction\PredictionInterface) {
231 throw new InvalidArgumentException(sprintf(
232 'Expected callable or instance of PredictionInterface, but got %s.',
237 $this->bindToObjectProphecy();
238 $this->prediction = $prediction;
244 * Sets call prediction to the prophecy.
246 * @see Prophecy\Prediction\CallPrediction
250 public function shouldBeCalled()
252 return $this->should(new Prediction\CallPrediction);
256 * Sets no calls prediction to the prophecy.
258 * @see Prophecy\Prediction\NoCallsPrediction
262 public function shouldNotBeCalled()
264 return $this->should(new Prediction\NoCallsPrediction);
268 * Sets call times prediction to the prophecy.
270 * @see Prophecy\Prediction\CallTimesPrediction
276 public function shouldBeCalledTimes($count)
278 return $this->should(new Prediction\CallTimesPrediction($count));
282 * Checks provided prediction immediately.
284 * @param callable|Prediction\PredictionInterface $prediction
288 * @throws \Prophecy\Exception\InvalidArgumentException
290 public function shouldHave($prediction)
292 if (is_callable($prediction)) {
293 $prediction = new Prediction\CallbackPrediction($prediction);
296 if (!$prediction instanceof Prediction\PredictionInterface) {
297 throw new InvalidArgumentException(sprintf(
298 'Expected callable or instance of PredictionInterface, but got %s.',
303 if (null === $this->promise && !$this->voidReturnType) {
307 $calls = $this->getObjectProphecy()->findProphecyMethodCalls(
308 $this->getMethodName(),
309 $this->getArgumentsWildcard()
313 $prediction->check($calls, $this->getObjectProphecy(), $this);
314 $this->checkedPredictions[] = $prediction;
315 } catch (\Exception $e) {
316 $this->checkedPredictions[] = $prediction;
325 * Checks call prediction.
327 * @see Prophecy\Prediction\CallPrediction
331 public function shouldHaveBeenCalled()
333 return $this->shouldHave(new Prediction\CallPrediction);
337 * Checks no calls prediction.
339 * @see Prophecy\Prediction\NoCallsPrediction
343 public function shouldNotHaveBeenCalled()
345 return $this->shouldHave(new Prediction\NoCallsPrediction);
349 * Checks no calls prediction.
351 * @see Prophecy\Prediction\NoCallsPrediction
356 public function shouldNotBeenCalled()
358 return $this->shouldNotHaveBeenCalled();
362 * Checks call times prediction.
364 * @see Prophecy\Prediction\CallTimesPrediction
370 public function shouldHaveBeenCalledTimes($count)
372 return $this->shouldHave(new Prediction\CallTimesPrediction($count));
376 * Checks currently registered [with should(...)] prediction.
378 public function checkPrediction()
380 if (null === $this->prediction) {
384 $this->shouldHave($this->prediction);
388 * Returns currently registered promise.
390 * @return null|Promise\PromiseInterface
392 public function getPromise()
394 return $this->promise;
398 * Returns currently registered prediction.
400 * @return null|Prediction\PredictionInterface
402 public function getPrediction()
404 return $this->prediction;
408 * Returns predictions that were checked on this object.
410 * @return Prediction\PredictionInterface[]
412 public function getCheckedPredictions()
414 return $this->checkedPredictions;
418 * Returns object prophecy this method prophecy is tied to.
420 * @return ObjectProphecy
422 public function getObjectProphecy()
424 return $this->objectProphecy;
428 * Returns method name.
432 public function getMethodName()
434 return $this->methodName;
438 * Returns arguments wildcard.
440 * @return Argument\ArgumentsWildcard
442 public function getArgumentsWildcard()
444 return $this->argumentsWildcard;
450 public function hasReturnVoid()
452 return $this->voidReturnType;
455 private function bindToObjectProphecy()
461 $this->getObjectProphecy()->addMethodProphecy($this);