Completed
Push — master ( 16044e...cf5113 )
by Dave
02:47
created

Expectation::andReturnFalse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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 [email protected] 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
21
namespace Mockery;
22
23
class Expectation implements ExpectationInterface
24
{
25
    /**
26
     * Mock object to which this expectation belongs
27
     *
28
     * @var object
29
     */
30
    protected $_mock = null;
31
32
    /**
33
     * Method name
34
     *
35
     * @var string
36
     */
37
    protected $_name = null;
38
39
    /**
40
     * Arguments expected by this expectation
41
     *
42
     * @var array
43
     */
44
    protected $_expectedArgs = array();
45
46
    /**
47
     * Count validator store
48
     *
49
     * @var array
50
     */
51
    protected $_countValidators = array();
52
53
    /**
54
     * The count validator class to use
55
     *
56
     * @var string
57
     */
58
    protected $_countValidatorClass = 'Mockery\CountValidator\Exact';
59
60
    /**
61
     * Actual count of calls to this expectation
62
     *
63
     * @var int
64
     */
65
    protected $_actualCount = 0;
66
67
    /**
68
     * Value to return from this expectation
69
     *
70
     * @var mixed
71
     */
72
    protected $_returnValue = null;
73
74
    /**
75
     * Array of return values as a queue for multiple return sequence
76
     *
77
     * @var array
78
     */
79
    protected $_returnQueue = array();
80
81
    /**
82
     * Array of closures executed with given arguments to generate a result
83
     * to be returned
84
     *
85
     * @var array
86
     */
87
    protected $_closureQueue = array();
88
89
    /**
90
     * Array of values to be set when this expectation matches
91
     *
92
     * @var array
93
     */
94
    protected $_setQueue = array();
95
96
    /**
97
     * Integer representing the call order of this expectation
98
     *
99
     * @var int
100
     */
101
    protected $_orderNumber = null;
102
103
    /**
104
     * Integer representing the call order of this expectation on a global basis
105
     *
106
     * @var int
107
     */
108
    protected $_globalOrderNumber = null;
109
110
    /**
111
     * Flag indicating that an exception is expected to be throw (not returned)
112
     *
113
     * @var bool
114
     */
115
    protected $_throw = false;
116
117
    /**
118
     * Flag indicating whether the order of calling is determined locally or
119
     * globally
120
     *
121
     * @var bool
122
     */
123
    protected $_globally = false;
124
125
    /**
126
     * Flag indicating we expect no arguments
127
     *
128
     * @var bool
129
     */
130
    protected $_noArgsExpectation = false;
131
132
    /**
133
     * Flag indicating if the return value should be obtained from the original
134
     * class method instead of returning predefined values from the return queue
135
     *
136
     * @var bool
137
     */
138
    protected $_passthru = false;
139
140
    /**
141
     * Constructor
142
     *
143
     * @param \Mockery\MockInterface $mock
144
     * @param string $name
145
     */
146 301
    public function __construct(\Mockery\MockInterface $mock, $name)
147
    {
148 301
        $this->_mock = $mock;
149 301
        $this->_name = $name;
150 301
    }
151
152
    /**
153
     * Return a string with the method name and arguments formatted
154
     *
155
     * @param string $name Name of the expected method
156
     * @param array $args List of arguments to the method
157
     * @return string
158
     */
159 45
    public function __toString()
160
    {
161 45
        return \Mockery::formatArgs($this->_name, $this->_expectedArgs);
162
    }
163
164
    /**
165
     * Verify the current call, i.e. that the given arguments match those
166
     * of this expectation
167
     *
168
     * @param array $args
169
     * @return mixed
170
     */
171 231
    public function verifyCall(array $args)
172
    {
173 231
        $this->validateOrder();
174 231
        $this->_actualCount++;
175 231
        if (true === $this->_passthru) {
176 3
            return $this->_mock->mockery_callSubjectMethod($this->_name, $args);
177
        }
178 229
        $return = $this->_getReturnValue($args);
179 229
        if ($return instanceof \Exception && $this->_throw === true) {
180 5
            throw $return;
181
        }
182 224
        $this->_setValues();
183 224
        return $return;
184
    }
185
186
    /**
187
     * Sets public properties with queued values to the mock object
188
     *
189
     * @param array $args
190
     * @return mixed
191
     */
192 224
    protected function _setValues()
193
    {
194 224
        foreach ($this->_setQueue as $name => &$values) {
195 8
            if (count($values) > 0) {
196 8
                $value = array_shift($values);
197 8
                $this->_mock->{$name} = $value;
198 8
            }
199 224
        }
200 224
    }
201
202
    /**
203
     * Fetch the return value for the matching args
204
     *
205
     * @param array $args
206
     * @return mixed
207
     */
208 229
    protected function _getReturnValue(array $args)
209
    {
210 229
        if (count($this->_closureQueue) > 1) {
211
            return call_user_func_array(array_shift($this->_closureQueue), $args);
212 229
        } elseif (count($this->_closureQueue) > 0) {
213 1
            return call_user_func_array(current($this->_closureQueue), $args);
214 228
        } elseif (count($this->_returnQueue) > 1) {
215 5
            return array_shift($this->_returnQueue);
216 227
        } elseif (count($this->_returnQueue) > 0) {
217 93
            return current($this->_returnQueue);
218
        }
219
220 134
        return $this->_mock->mockery_returnValueForMethod($this->_name);
221
    }
222
223
    /**
224
     * Checks if this expectation is eligible for additional calls
225
     *
226
     * @return bool
227
     */
228 272
    public function isEligible()
229
    {
230 272
        foreach ($this->_countValidators as $validator) {
231 137
            if (!$validator->isEligible($this->_actualCount)) {
232 22
                return false;
233
            }
234 269
        }
235 269
        return true;
236
    }
237
238
    /**
239
     * Check if there is a constraint on call count
240
     *
241
     * @return bool
242
     */
243
    public function isCallCountConstrained()
244
    {
245
        return (count($this->_countValidators) > 0);
246
    }
247
248
    /**
249
     * Verify call order
250
     *
251
     * @return void
252
     */
253 231
    public function validateOrder()
254
    {
255 231
        if ($this->_orderNumber) {
256 17
            $this->_mock->mockery_validateOrder((string) $this, $this->_orderNumber, $this->_mock);
257 17
        }
258 231
        if ($this->_globalOrderNumber) {
259 1
            $this->_mock->mockery_getContainer()
260 1
                ->mockery_validateOrder((string) $this, $this->_globalOrderNumber, $this->_mock);
261 1
        }
262 231
    }
263
264
    /**
265
     * Verify this expectation
266
     *
267
     * @return bool
268
     */
269 142
    public function verify()
270
    {
271 142
        foreach ($this->_countValidators as $validator) {
272 115
            $validator->validate($this->_actualCount);
273 126
        }
274 124
    }
275
276
    /**
277
     * Check if passed arguments match an argument expectation
278
     *
279
     * @param array $args
280
     * @return bool
281
     */
282 277
    public function matchArgs(array $args)
283
    {
284 277
        if (empty($this->_expectedArgs) && !$this->_noArgsExpectation) {
285 159
            return true;
286
        }
287 121
        $expectedArgsCount = count($this->_expectedArgs);
288 121
        if ($expectedArgsCount === 1 && ($this->_expectedArgs[0] instanceof \Mockery\Matcher\MultiArgumentClosure)) {
289 6
            if ($this->_matchArg($this->_expectedArgs[0], $args)) {
290 4
                return true;
291
            }
292 2
            return false;
293
        }
294 115
        if (count($args) !== $expectedArgsCount) {
295 8
            return false;
296
        }
297 109
        $argCount = count($args);
298 109
        for ($i=0; $i<$argCount; $i++) {
299 106
            $param =& $args[$i];
300 106
            if (!$this->_matchArg($this->_expectedArgs[$i], $param)) {
301 47
                return false;
302
            }
303 68
        }
304
305 71
        return true;
306
    }
307
308
    /**
309
     * Check if passed argument matches an argument expectation
310
     *
311
     * @param array $args
312
     * @return bool
313
     */
314 112
    protected function _matchArg($expected, &$actual)
315
    {
316 112
        if ($expected === $actual) {
317 29
            return true;
318
        }
319 95
        if (!is_object($expected) && !is_object($actual) && $expected == $actual) {
320 1
            return true;
321
        }
322 94
        if (is_string($expected) && !is_array($actual) && !is_object($actual)) {
323
            # push/pop an error handler here to to make sure no error/exception thrown if $expected is not a regex
324
            set_error_handler(function () {});
325 6
            $result = preg_match($expected, (string) $actual);
326 6
            restore_error_handler();
327
328 6
            if ($result) {
329 3
                return true;
330
            }
331 3
        }
332 93
        if (is_string($expected) && is_object($actual)) {
333 1
            $result = $actual instanceof $expected;
334 1
            if ($result) {
335 1
                return true;
336
            }
337
        }
338 92
        if ($expected instanceof \Mockery\Matcher\MatcherAbstract) {
339 70
            return $expected->match($actual);
340
        }
341 22
        if ($expected instanceof \Hamcrest\Matcher || $expected instanceof \Hamcrest_Matcher) {
0 ignored issues
show
Bug introduced by
The class Hamcrest_Matcher does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
342 3
            return $expected->matches($actual);
343
        }
344 19
        return false;
345
    }
346
347
    /**
348
     * Expected argument setter for the expectation
349
     *
350
     * @param mixed ...
351
     * @return self
352
     */
353 137
    public function with()
354
    {
355 137
        return $this->withArgs(func_get_args());
356
    }
357
358
    /**
359
     * Expected arguments for the expectation passed as an array
360
     *
361
     * @param array|\Closure $argsOrClosure
362
     * @return self
363
     */
364 149
    public function withArgs($argsOrClosure)
365
    {
366 149
        if (is_array($argsOrClosure)) {
367 142
            if (empty($argsOrClosure)) {
368 6
                return $this->withNoArgs();
369
            }
370 139
            $this->_expectedArgs = $argsOrClosure;
371 146
        } elseif (is_object($argsOrClosure) && ($argsOrClosure instanceof \Closure)) {
372 6
            $this->_expectedArgs = [new \Mockery\Matcher\MultiArgumentClosure($argsOrClosure)];
373 6
        } else {
374 1
            throw new \InvalidArgumentException(sprintf('Call to %s with an invalid argument (%s), only array and '.
375 1
                'closure are allowed', __METHOD__, $argsOrClosure));
376
        }
377 145
        $this->_noArgsExpectation = false;
378 145
        return $this;
379
    }
380
381
    /**
382
     * Set with() as no arguments expected
383
     *
384
     * @return self
385
     */
386 10
    public function withNoArgs()
387
    {
388 10
        $this->_noArgsExpectation = true;
389 10
        $this->_expectedArgs = null;
390 10
        return $this;
391
    }
392
393
    /**
394
     * Set expectation that any arguments are acceptable
395
     *
396
     * @return self
397
     */
398 2
    public function withAnyArgs()
399
    {
400 2
        $this->_expectedArgs = array();
401 2
        return $this;
402
    }
403
404
    /**
405
     * Set a return value, or sequential queue of return values
406
     *
407
     * @param mixed ...
408
     * @return self
409
     */
410 108
    public function andReturn()
411
    {
412 108
        $this->_returnQueue = func_get_args();
413 108
        return $this;
414
    }
415
416
    /**
417
     * Return this mock, like a fluent interface
418
     *
419
     * @return self
420
     */
421 1
    public function andReturnSelf()
422
    {
423 1
        return $this->andReturn($this->_mock);
424
    }
425
426
    /**
427
     * Set a sequential queue of return values with an array
428
     *
429
     * @param array $values
430
     * @return self
431
     */
432 2
    public function andReturnValues(array $values)
433
    {
434 2
        call_user_func_array(array($this, 'andReturn'), $values);
435 2
        return $this;
436
    }
437
438
    /**
439
     * Set a closure or sequence of closures with which to generate return
440
     * values. The arguments passed to the expected method are passed to the
441
     * closures as parameters.
442
     *
443
     * @param callable ...
444
     * @return self
445
     */
446 1
    public function andReturnUsing()
447
    {
448 1
        $this->_closureQueue = func_get_args();
449 1
        return $this;
450
    }
451
452
    /**
453
     * Return a self-returning black hole object.
454
     *
455
     * @return self
456
     */
457 1
    public function andReturnUndefined()
458
    {
459 1
        $this->andReturn(new \Mockery\Undefined);
460 1
        return $this;
461
    }
462
463
    /**
464
     * Return null. This is merely a language construct for Mock describing.
465
     *
466
     * @return self
467
     */
468 1
    public function andReturnNull()
469
    {
470 1
        return $this;
471
    }
472
473 1
    public function andReturnFalse()
474
    {
475 1
        return $this->andReturn(false);
476
    }
477
478 1
    public function andReturnTrue()
479
    {
480 1
        return $this->andReturn(true);
481
    }
482
483
    /**
484
     * Set Exception class and arguments to that class to be thrown
485
     *
486
     * @param string|\Exception $exception
487
     * @param string $message
488
     * @param int $code
489
     * @param \Exception $previous
490
     * @return self
491
     */
492 4
    public function andThrow($exception, $message = '', $code = 0, \Exception $previous = null)
493
    {
494 4
        $this->_throw = true;
495 4
        if (is_object($exception)) {
496 2
            $this->andReturn($exception);
497 2
        } else {
498 2
            $this->andReturn(new $exception($message, $code, $previous));
499
        }
500 4
        return $this;
501
    }
502
503
    /**
504
     * Set Exception classes to be thrown
505
     *
506
     * @param array $exceptions
507
     * @return self
508
     */
509 2
    public function andThrowExceptions(array $exceptions)
510
    {
511 2
        $this->_throw = true;
512 2
        foreach ($exceptions as $exception) {
513 2
            if (!is_object($exception)) {
514 1
                throw new Exception('You must pass an array of exception objects to andThrowExceptions');
515
            }
516 1
        }
517 1
        return $this->andReturnValues($exceptions);
518
    }
519
520
    /**
521
     * Register values to be set to a public property each time this expectation occurs
522
     *
523
     * @param string $name
524
     * @param mixed $value
525
     * @return self
526
     */
527 8
    public function andSet($name, $value)
528
    {
529 8
        $values = func_get_args();
530 8
        array_shift($values);
531 8
        $this->_setQueue[$name] = $values;
532 8
        return $this;
533
    }
534
535
    /**
536
     * Alias to andSet(). Allows the natural English construct
537
     * - set('foo', 'bar')->andReturn('bar')
538
     *
539
     * @param string $name
540
     * @param mixed $value
541
     * @return self
542
     */
543 3
    public function set($name, $value)
544
    {
545 3
        return call_user_func_array(array($this, 'andSet'), func_get_args());
546
    }
547
548
    /**
549
     * Indicates this expectation should occur zero or more times
550
     *
551
     * @return self
552
     */
553 2
    public function zeroOrMoreTimes()
554
    {
555 2
        $this->atLeast()->never();
556 2
    }
557
558
    /**
559
     * Indicates the number of times this expectation should occur
560
     *
561
     * @param int $limit
562
     * @return self
563
     */
564 152
    public function times($limit = null)
565
    {
566 152
        if (is_null($limit)) {
567
            return $this;
568
        }
569 152
        $this->_countValidators[] = new $this->_countValidatorClass($this, $limit);
570 152
        $this->_countValidatorClass = 'Mockery\CountValidator\Exact';
571 152
        return $this;
572
    }
573
574
    /**
575
     * Indicates that this expectation is never expected to be called
576
     *
577
     * @return self
578
     */
579 37
    public function never()
580
    {
581 37
        return $this->times(0);
582
    }
583
584
    /**
585
     * Indicates that this expectation is expected exactly once
586
     *
587
     * @return self
588
     */
589 104
    public function once()
590
    {
591 104
        return $this->times(1);
592
    }
593
594
    /**
595
     * Indicates that this expectation is expected exactly twice
596
     *
597
     * @return self
598
     */
599 18
    public function twice()
600
    {
601 18
        return $this->times(2);
602
    }
603
604
    /**
605
     * Sets next count validator to the AtLeast instance
606
     *
607
     * @return self
608
     */
609 13
    public function atLeast()
610
    {
611 13
        $this->_countValidatorClass = 'Mockery\CountValidator\AtLeast';
612 13
        return $this;
613
    }
614
615
    /**
616
     * Sets next count validator to the AtMost instance
617
     *
618
     * @return self
619
     */
620 7
    public function atMost()
621
    {
622 7
        $this->_countValidatorClass = 'Mockery\CountValidator\AtMost';
623 7
        return $this;
624
    }
625
626
    /**
627
     * Shorthand for setting minimum and maximum constraints on call counts
628
     *
629
     * @param int $minimum
630
     * @param int $maximum
631
     */
632
    public function between($minimum, $maximum)
633
    {
634
        return $this->atLeast()->times($minimum)->atMost()->times($maximum);
635
    }
636
637
    /**
638
     * Indicates that this expectation must be called in a specific given order
639
     *
640
     * @param string $group Name of the ordered group
641
     * @return self
642
     */
643 20
    public function ordered($group = null)
644
    {
645 20
        if ($this->_globally) {
646 1
            $this->_globalOrderNumber = $this->_defineOrdered($group, $this->_mock->mockery_getContainer());
647 1
        } else {
648 19
            $this->_orderNumber = $this->_defineOrdered($group, $this->_mock);
649
        }
650 20
        $this->_globally = false;
651 20
        return $this;
652
    }
653
654
    /**
655
     * Indicates call order should apply globally
656
     *
657
     * @return self
658
     */
659 1
    public function globally()
660
    {
661 1
        $this->_globally = true;
662 1
        return $this;
663
    }
664
665
    /**
666
     * Setup the ordering tracking on the mock or mock container
667
     *
668
     * @param string $group
669
     * @param object $ordering
670
     * @return int
671
     */
672 20
    protected function _defineOrdered($group, $ordering)
673
    {
674 20
        $groups = $ordering->mockery_getGroups();
675 20
        if (is_null($group)) {
676 19
            $result = $ordering->mockery_allocateOrder();
677 20
        } elseif (isset($groups[$group])) {
678 2
            $result = $groups[$group];
679 2
        } else {
680 4
            $result = $ordering->mockery_allocateOrder();
681 4
            $ordering->mockery_setGroup($group, $result);
682
        }
683 20
        return $result;
684
    }
685
686
    /**
687
     * Return order number
688
     *
689
     * @return int
690
     */
691 1
    public function getOrderNumber()
692
    {
693 1
        return $this->_orderNumber;
694
    }
695
696
    /**
697
     * Mark this expectation as being a default
698
     *
699
     * @return self
700
     */
701 24
    public function byDefault()
702
    {
703 24
        $director = $this->_mock->mockery_getExpectationsFor($this->_name);
704 24
        if (!empty($director)) {
705 24
            $director->makeExpectationDefault($this);
706 23
        }
707 23
        return $this;
708
    }
709
710
    /**
711
     * Return the parent mock of the expectation
712
     *
713
     * @return \Mockery\MockInterface
714
     */
715 27
    public function getMock()
716
    {
717 27
        return $this->_mock;
718
    }
719
720
    /**
721
     * Flag this expectation as calling the original class method with the
722
     * any provided arguments instead of using a return value queue.
723
     *
724
     * @return self
725
     */
726 3
    public function passthru()
727
    {
728 3
        if ($this->_mock instanceof Mock) {
729
            throw new Exception(
730
                'Mock Objects not created from a loaded/existing class are '
731
                . 'incapable of passing method calls through to a parent class'
732
            );
733
        }
734 3
        $this->_passthru = true;
735 3
        return $this;
736
    }
737
738
    /**
739
     * Cloning logic
740
     *
741
     */
742 8
    public function __clone()
743
    {
744 8
        $newValidators = array();
745 8
        $countValidators = $this->_countValidators;
746 8
        foreach ($countValidators as $validator) {
747 5
            $newValidators[] = clone $validator;
748 8
        }
749 8
        $this->_countValidators = $newValidators;
750 8
    }
751
752 5
    public function getName()
753
    {
754 5
        return $this->_name;
755
    }
756
}
757