Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / phpspec / prophecy / src / Prophecy / Prophecy / MethodProphecy.php
1 <?php
2
3 /*
4  * This file is part of the Prophecy.
5  * (c) Konstantin Kudryashov <ever.zet@gmail.com>
6  *     Marcello Duarte <marcello.duarte@gmail.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Prophecy\Prophecy;
13
14 use Prophecy\Argument;
15 use Prophecy\Prophet;
16 use Prophecy\Promise;
17 use Prophecy\Prediction;
18 use Prophecy\Exception\Doubler\MethodNotFoundException;
19 use Prophecy\Exception\InvalidArgumentException;
20 use Prophecy\Exception\Prophecy\MethodProphecyException;
21
22 /**
23  * Method prophecy.
24  *
25  * @author Konstantin Kudryashov <ever.zet@gmail.com>
26  */
27 class MethodProphecy
28 {
29     private $objectProphecy;
30     private $methodName;
31     private $argumentsWildcard;
32     private $promise;
33     private $prediction;
34     private $checkedPredictions = array();
35     private $bound = false;
36     private $voidReturnType = false;
37
38     /**
39      * Initializes method prophecy.
40      *
41      * @param ObjectProphecy                        $objectProphecy
42      * @param string                                $methodName
43      * @param null|Argument\ArgumentsWildcard|array $arguments
44      *
45      * @throws \Prophecy\Exception\Doubler\MethodNotFoundException If method not found
46      */
47     public function __construct(ObjectProphecy $objectProphecy, $methodName, $arguments = null)
48     {
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);
54         }
55
56         $this->objectProphecy = $objectProphecy;
57         $this->methodName     = $methodName;
58
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.",
64                 get_class($double),
65                 $methodName
66             ), $this);
67         }
68
69         if (null !== $arguments) {
70             $this->withArguments($arguments);
71         }
72
73         if (version_compare(PHP_VERSION, '7.0', '>=') && true === $reflectedMethod->hasReturnType()) {
74             $type = (string) $reflectedMethod->getReturnType();
75
76             if ('void' === $type) {
77                 $this->voidReturnType = true;
78             }
79
80             $this->will(function () use ($type) {
81                 switch ($type) {
82                     case 'void': return;
83                     case 'string': return '';
84                     case 'float':  return 0.0;
85                     case 'int':    return 0;
86                     case 'bool':   return false;
87                     case 'array':  return array();
88
89                     case 'callable':
90                     case 'Closure':
91                         return function () {};
92
93                     case 'Traversable':
94                     case 'Generator':
95                         // Remove eval() when minimum version >=5.5
96                         /** @var callable $generator */
97                         $generator = eval('return function () { yield; };');
98                         return $generator();
99
100                     default:
101                         $prophet = new Prophet;
102                         return $prophet->prophesize($type)->reveal();
103                 }
104             });
105         }
106     }
107
108     /**
109      * Sets argument wildcard.
110      *
111      * @param array|Argument\ArgumentsWildcard $arguments
112      *
113      * @return $this
114      *
115      * @throws \Prophecy\Exception\InvalidArgumentException
116      */
117     public function withArguments($arguments)
118     {
119         if (is_array($arguments)) {
120             $arguments = new Argument\ArgumentsWildcard($arguments);
121         }
122
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.',
127                 gettype($arguments)
128             ));
129         }
130
131         $this->argumentsWildcard = $arguments;
132
133         return $this;
134     }
135
136     /**
137      * Sets custom promise to the prophecy.
138      *
139      * @param callable|Promise\PromiseInterface $promise
140      *
141      * @return $this
142      *
143      * @throws \Prophecy\Exception\InvalidArgumentException
144      */
145     public function will($promise)
146     {
147         if (is_callable($promise)) {
148             $promise = new Promise\CallbackPromise($promise);
149         }
150
151         if (!$promise instanceof Promise\PromiseInterface) {
152             throw new InvalidArgumentException(sprintf(
153                 'Expected callable or instance of PromiseInterface, but got %s.',
154                 gettype($promise)
155             ));
156         }
157
158         $this->bindToObjectProphecy();
159         $this->promise = $promise;
160
161         return $this;
162     }
163
164     /**
165      * Sets return promise to the prophecy.
166      *
167      * @see \Prophecy\Promise\ReturnPromise
168      *
169      * @return $this
170      */
171     public function willReturn()
172     {
173         if ($this->voidReturnType) {
174             throw new MethodProphecyException(
175                 "The method \"$this->methodName\" has a void return type, and so cannot return anything",
176                 $this
177             );
178         }
179
180         return $this->will(new Promise\ReturnPromise(func_get_args()));
181     }
182
183     /**
184      * Sets return argument promise to the prophecy.
185      *
186      * @param int $index The zero-indexed number of the argument to return
187      *
188      * @see \Prophecy\Promise\ReturnArgumentPromise
189      *
190      * @return $this
191      */
192     public function willReturnArgument($index = 0)
193     {
194         if ($this->voidReturnType) {
195             throw new MethodProphecyException("The method \"$this->methodName\" has a void return type", $this);
196         }
197
198         return $this->will(new Promise\ReturnArgumentPromise($index));
199     }
200
201     /**
202      * Sets throw promise to the prophecy.
203      *
204      * @see \Prophecy\Promise\ThrowPromise
205      *
206      * @param string|\Exception $exception Exception class or instance
207      *
208      * @return $this
209      */
210     public function willThrow($exception)
211     {
212         return $this->will(new Promise\ThrowPromise($exception));
213     }
214
215     /**
216      * Sets custom prediction to the prophecy.
217      *
218      * @param callable|Prediction\PredictionInterface $prediction
219      *
220      * @return $this
221      *
222      * @throws \Prophecy\Exception\InvalidArgumentException
223      */
224     public function should($prediction)
225     {
226         if (is_callable($prediction)) {
227             $prediction = new Prediction\CallbackPrediction($prediction);
228         }
229
230         if (!$prediction instanceof Prediction\PredictionInterface) {
231             throw new InvalidArgumentException(sprintf(
232                 'Expected callable or instance of PredictionInterface, but got %s.',
233                 gettype($prediction)
234             ));
235         }
236
237         $this->bindToObjectProphecy();
238         $this->prediction = $prediction;
239
240         return $this;
241     }
242
243     /**
244      * Sets call prediction to the prophecy.
245      *
246      * @see \Prophecy\Prediction\CallPrediction
247      *
248      * @return $this
249      */
250     public function shouldBeCalled()
251     {
252         return $this->should(new Prediction\CallPrediction);
253     }
254
255     /**
256      * Sets no calls prediction to the prophecy.
257      *
258      * @see \Prophecy\Prediction\NoCallsPrediction
259      *
260      * @return $this
261      */
262     public function shouldNotBeCalled()
263     {
264         return $this->should(new Prediction\NoCallsPrediction);
265     }
266
267     /**
268      * Sets call times prediction to the prophecy.
269      *
270      * @see \Prophecy\Prediction\CallTimesPrediction
271      *
272      * @param $count
273      *
274      * @return $this
275      */
276     public function shouldBeCalledTimes($count)
277     {
278         return $this->should(new Prediction\CallTimesPrediction($count));
279     }
280
281     /**
282      * Sets call times prediction to the prophecy.
283      *
284      * @see \Prophecy\Prediction\CallTimesPrediction
285      *
286      * @return $this
287      */
288     public function shouldBeCalledOnce()
289     {
290         return $this->shouldBeCalledTimes(1);
291     }
292
293     /**
294      * Checks provided prediction immediately.
295      *
296      * @param callable|Prediction\PredictionInterface $prediction
297      *
298      * @return $this
299      *
300      * @throws \Prophecy\Exception\InvalidArgumentException
301      */
302     public function shouldHave($prediction)
303     {
304         if (is_callable($prediction)) {
305             $prediction = new Prediction\CallbackPrediction($prediction);
306         }
307
308         if (!$prediction instanceof Prediction\PredictionInterface) {
309             throw new InvalidArgumentException(sprintf(
310                 'Expected callable or instance of PredictionInterface, but got %s.',
311                 gettype($prediction)
312             ));
313         }
314
315         if (null === $this->promise && !$this->voidReturnType) {
316             $this->willReturn();
317         }
318
319         $calls = $this->getObjectProphecy()->findProphecyMethodCalls(
320             $this->getMethodName(),
321             $this->getArgumentsWildcard()
322         );
323
324         try {
325             $prediction->check($calls, $this->getObjectProphecy(), $this);
326             $this->checkedPredictions[] = $prediction;
327         } catch (\Exception $e) {
328             $this->checkedPredictions[] = $prediction;
329
330             throw $e;
331         }
332
333         return $this;
334     }
335
336     /**
337      * Checks call prediction.
338      *
339      * @see \Prophecy\Prediction\CallPrediction
340      *
341      * @return $this
342      */
343     public function shouldHaveBeenCalled()
344     {
345         return $this->shouldHave(new Prediction\CallPrediction);
346     }
347
348     /**
349      * Checks no calls prediction.
350      *
351      * @see \Prophecy\Prediction\NoCallsPrediction
352      *
353      * @return $this
354      */
355     public function shouldNotHaveBeenCalled()
356     {
357         return $this->shouldHave(new Prediction\NoCallsPrediction);
358     }
359
360     /**
361      * Checks no calls prediction.
362      *
363      * @see \Prophecy\Prediction\NoCallsPrediction
364      * @deprecated
365      *
366      * @return $this
367      */
368     public function shouldNotBeenCalled()
369     {
370         return $this->shouldNotHaveBeenCalled();
371     }
372
373     /**
374      * Checks call times prediction.
375      *
376      * @see \Prophecy\Prediction\CallTimesPrediction
377      *
378      * @param int $count
379      *
380      * @return $this
381      */
382     public function shouldHaveBeenCalledTimes($count)
383     {
384         return $this->shouldHave(new Prediction\CallTimesPrediction($count));
385     }
386
387     /**
388      * Checks call times prediction.
389      *
390      * @see \Prophecy\Prediction\CallTimesPrediction
391      *
392      * @return $this
393      */
394     public function shouldHaveBeenCalledOnce()
395     {
396         return $this->shouldHaveBeenCalledTimes(1);
397     }
398
399     /**
400      * Checks currently registered [with should(...)] prediction.
401      */
402     public function checkPrediction()
403     {
404         if (null === $this->prediction) {
405             return;
406         }
407
408         $this->shouldHave($this->prediction);
409     }
410
411     /**
412      * Returns currently registered promise.
413      *
414      * @return null|Promise\PromiseInterface
415      */
416     public function getPromise()
417     {
418         return $this->promise;
419     }
420
421     /**
422      * Returns currently registered prediction.
423      *
424      * @return null|Prediction\PredictionInterface
425      */
426     public function getPrediction()
427     {
428         return $this->prediction;
429     }
430
431     /**
432      * Returns predictions that were checked on this object.
433      *
434      * @return Prediction\PredictionInterface[]
435      */
436     public function getCheckedPredictions()
437     {
438         return $this->checkedPredictions;
439     }
440
441     /**
442      * Returns object prophecy this method prophecy is tied to.
443      *
444      * @return ObjectProphecy
445      */
446     public function getObjectProphecy()
447     {
448         return $this->objectProphecy;
449     }
450
451     /**
452      * Returns method name.
453      *
454      * @return string
455      */
456     public function getMethodName()
457     {
458         return $this->methodName;
459     }
460
461     /**
462      * Returns arguments wildcard.
463      *
464      * @return Argument\ArgumentsWildcard
465      */
466     public function getArgumentsWildcard()
467     {
468         return $this->argumentsWildcard;
469     }
470
471     /**
472      * @return bool
473      */
474     public function hasReturnVoid()
475     {
476         return $this->voidReturnType;
477     }
478
479     private function bindToObjectProphecy()
480     {
481         if ($this->bound) {
482             return;
483         }
484
485         $this->getObjectProphecy()->addMethodProphecy($this);
486         $this->bound = true;
487     }
488 }