Mock   F
last analyzed

Complexity

Total Complexity 127

Size/Duplication

Total Lines 830
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 14

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 830
ccs 0
cts 303
cp 0
rs 1.263
wmc 127
lcom 4
cbo 14

47 Methods

Rating   Name   Duplication   Size   Complexity  
B mockery_init() 0 18 7
A shouldNotReceive() 0 10 2
A makePartial() 0 4 1
A __toString() 0 4 1
A mockery_callSubjectMethod() 0 4 1
A mockery_getMockableMethods() 0 4 1
A shouldAllowMockingMethod() 0 5 1
A shouldIgnoreMissing() 0 6 1
A asUndefined() 0 6 1
A shouldAllowMockingProtectedMethods() 0 5 1
A shouldDeferMissing() 0 5 1
A byDefault() 0 10 3
A __call() 0 4 1
A __callStatic() 0 4 1
B mockery_verify() 0 14 5
A mockery_teardown() 0 3 1
A mockery_allocateOrder() 0 5 1
A mockery_setGroup() 0 4 1
A mockery_getGroups() 0 4 1
A mockery_setCurrentOrder() 0 5 1
A mockery_getCurrentOrder() 0 4 1
A mockery_validateOrder() 0 16 2
A mockery_getExpectationCount() 0 8 2
A mockery_setExpectationsFor() 0 4 1
A mockery_getExpectationsFor() 0 6 2
A mockery_findExpectation() 0 9 2
A mockery_getContainer() 0 4 1
A mockery_getName() 0 4 1
A mockery_getMockableProperties() 0 4 1
A __isset() 0 8 3
A mockery_getExpectations() 0 4 1
D shouldReceive() 0 42 9
A allows() 0 12 3
A expects() 0 4 1
A mockery_isAnonymous() 0 12 2
A __wakeup() 0 9 1
A __destruct() 0 6 1
A mockery_getMethod() 0 10 3
C mockery_returnValueForMethod() 0 41 16
A shouldHaveReceived() 0 16 3
A shouldNotHaveReceived() 0 16 3
A _mockery_handleStaticMethodCall() 0 12 2
A _mockery_getReceivedMethodCalls() 0 4 2
C _mockery_handleMethodCall() 0 69 26
A mockery_getMethods() 0 14 3
A hasMethodOverloadingInParentClass() 0 5 1
A getNonPublicMethods() 0 11 1

How to fix   Complexity   

Complex Class

Complex classes like Mock often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Mock, and based on these observations, apply Extract Interface, too.

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 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
use Mockery\HigherOrderMessage;
24
use Mockery\MockInterface;
25
use Mockery\ExpectsHigherOrderMessage;
26
27
class Mock implements MockInterface
28
{
29
    /**
30
     * Stores an array of all expectation directors for this mock
31
     *
32
     * @var array
33
     */
34
    protected $_mockery_expectations = array();
35
36
    /**
37
     * Stores an inital number of expectations that can be manipulated
38
     * while using the getter method.
39
     *
40
     * @var int
41
     */
42
    protected $_mockery_expectations_count = 0;
43
44
    /**
45
     * Flag to indicate whether we can ignore method calls missing from our
46
     * expectations
47
     *
48
     * @var bool
49
     */
50
    protected $_mockery_ignoreMissing = false;
51
52
    /**
53
     * Flag to indicate whether we can defer method calls missing from our
54
     * expectations
55
     *
56
     * @var bool
57
     */
58
    protected $_mockery_deferMissing = false;
59
60
    /**
61
     * Flag to indicate whether this mock was verified
62
     *
63
     * @var bool
64
     */
65
    protected $_mockery_verified = false;
66
67
    /**
68
     * Given name of the mock
69
     *
70
     * @var string
71
     */
72
    protected $_mockery_name = null;
73
74
    /**
75
     * Order number of allocation
76
     *
77
     * @var int
78
     */
79
    protected $_mockery_allocatedOrder = 0;
80
81
    /**
82
     * Current ordered number
83
     *
84
     * @var int
85
     */
86
    protected $_mockery_currentOrder = 0;
87
88
    /**
89
     * Ordered groups
90
     *
91
     * @var array
92
     */
93
    protected $_mockery_groups = array();
94
95
    /**
96
     * Mock container containing this mock object
97
     *
98
     * @var \Mockery\Container
99
     */
100
    protected $_mockery_container = null;
101
102
    /**
103
     * Instance of a core object on which methods are called in the event
104
     * it has been set, and an expectation for one of the object's methods
105
     * does not exist. This implements a simple partial mock proxy system.
106
     *
107
     * @var object
108
     */
109
    protected $_mockery_partial = null;
110
111
    /**
112
     * Flag to indicate we should ignore all expectations temporarily. Used
113
     * mainly to prevent expectation matching when in the middle of a mock
114
     * object recording session.
115
     *
116
     * @var bool
117
     */
118
    protected $_mockery_disableExpectationMatching = false;
119
120
    /**
121
     * Stores all stubbed public methods separate from any on-object public
122
     * properties that may exist.
123
     *
124
     * @var array
125
     */
126
    protected $_mockery_mockableProperties = array();
127
128
    /**
129
     * @var array
130
     */
131
    protected $_mockery_mockableMethods = array();
132
133
    /**
134
     * Just a local cache for this mock's target's methods
135
     *
136
     * @var \ReflectionMethod[]
137
     */
138
    protected static $_mockery_methods;
139
140
    protected $_mockery_allowMockingProtectedMethods = false;
141
142
    protected $_mockery_receivedMethodCalls;
143
144
    /**
145
     * If shouldIgnoreMissing is called, this value will be returned on all calls to missing methods
146
     * @var mixed
147
     */
148
    protected $_mockery_defaultReturnValue = null;
149
150
    /**
151
     * We want to avoid constructors since class is copied to Generator.php
152
     * for inclusion on extending class definitions.
153
     *
154
     * @param \Mockery\Container $container
155
     * @param object $partialObject
156
     * @return void
157
     */
158
    public function mockery_init(\Mockery\Container $container = null, $partialObject = null)
159
    {
160
        if (is_null($container)) {
161
            $container = new \Mockery\Container;
162
        }
163
        $this->_mockery_container = $container;
164
        if (!is_null($partialObject)) {
165
            $this->_mockery_partial = $partialObject;
166
        }
167
168
        if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed()) {
169
            foreach ($this->mockery_getMethods() as $method) {
170
                if ($method->isPublic() && !$method->isStatic()) {
171
                    $this->_mockery_mockableMethods[] = $method->getName();
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
172
                }
173
            }
174
        }
175
    }
176
177
    /**
178
     * Set expected method calls
179
     *
180
     * @param array $methodNames,... one or many methods that are expected to be called in this mock
0 ignored issues
show
Documentation introduced by
There is no parameter named $methodNames,.... Did you maybe mean $methodNames?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
181
     *
182
     * @return \Mockery\ExpectationInterface|\Mockery\HigherOrderMessage
183
     */
184
    public function shouldReceive(...$methodNames)
185
    {
186
        if (count($methodNames) === 0) {
187
            return new HigherOrderMessage($this, "shouldReceive");
188
        }
189
190
        foreach ($methodNames as $method) {
191
            if ("" == $method) {
192
                throw new \InvalidArgumentException("Received empty method name");
193
            }
194
        }
195
196
        /** @var array $nonPublicMethods */
197
        $nonPublicMethods = $this->getNonPublicMethods();
198
199
        $self = $this;
200
        $allowMockingProtectedMethods = $this->_mockery_allowMockingProtectedMethods;
201
202
        $lastExpectation = \Mockery::parseShouldReturnArgs(
203
            $this, $methodNames, function ($method) use ($self, $nonPublicMethods, $allowMockingProtectedMethods) {
204
                $rm = $self->mockery_getMethod($method);
205
                if ($rm) {
206
                    if ($rm->isPrivate()) {
207
                        throw new \InvalidArgumentException("$method() cannot be mocked as it is a private method");
208
                    }
209
                    if (!$allowMockingProtectedMethods && $rm->isProtected()) {
210
                        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.");
211
                    }
212
                }
213
214
                $director = $self->mockery_getExpectationsFor($method);
215
                if (!$director) {
216
                    $director = new \Mockery\ExpectationDirector($method, $self);
217
                    $self->mockery_setExpectationsFor($method, $director);
218
                }
219
                $expectation = new \Mockery\Expectation($self, $method);
220
                $director->addExpectation($expectation);
221
                return $expectation;
222
            }
223
        );
224
        return $lastExpectation;
225
    }
226
227
    // start method allows
228
    /**
229
     * @return self
230
     */
231
    public function allows(array $stubs = [])
232
    {
233
        if (empty($stubs)) {
234
            return $this->shouldReceive();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->shouldReceive(); (Mockery\HigherOrderMessa...ry\CompositeExpectation) is incompatible with the return type documented by Mockery\Mock::allows of type Mockery\Mock.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
235
        }
236
237
        foreach ($stubs as $method => $returnValue) {
238
            $this->shouldReceive($method)->andReturn($returnValue);
0 ignored issues
show
Bug introduced by
The method andReturn does only exist in Mockery\CompositeExpectation, but not in Mockery\HigherOrderMessage.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
239
        }
240
241
        return $this;
242
    }
243
    // end method allows
244
245
    // start method expects
246
    /**
247
     * @return ExpectsHigherOrderMessage
248
     */
249
    public function expects()
250
    {
251
        return new ExpectsHigherOrderMessage($this);
252
    }
253
    // end method expects
254
255
    /**
256
     * Shortcut method for setting an expectation that a method should not be called.
257
     *
258
     * @param array $methodNames one or many methods that are expected not to be called in this mock
259
     * @return \Mockery\Expectation|\Mockery\HigherOrderMessage
260
     */
261
    public function shouldNotReceive(...$methodNames)
262
    {
263
        if (count($methodNames) === 0) {
264
            return new HigherOrderMessage($this, "shouldNotReceive");
265
        }
266
267
        $expectation = call_user_func_array(array($this, 'shouldReceive'), $methodNames);
268
        $expectation->never();
269
        return $expectation;
270
    }
271
272
    /**
273
     * Allows additional methods to be mocked that do not explicitly exist on mocked class
274
     * @param String $method name of the method to be mocked
275
     * @return Mock
276
     */
277
    public function shouldAllowMockingMethod($method)
278
    {
279
        $this->_mockery_mockableMethods[] = $method;
280
        return $this;
281
    }
282
283
    /**
284
     * Set mock to ignore unexpected methods and return Undefined class
285
     * @param mixed $returnValue the default return value for calls to missing functions on this mock
286
     * @return Mock
287
     */
288
    public function shouldIgnoreMissing($returnValue = null)
289
    {
290
        $this->_mockery_ignoreMissing = true;
291
        $this->_mockery_defaultReturnValue = $returnValue;
292
        return $this;
293
    }
294
295
    public function asUndefined()
296
    {
297
        $this->_mockery_ignoreMissing = true;
298
        $this->_mockery_defaultReturnValue = new \Mockery\Undefined;
299
        return $this;
300
    }
301
302
    /**
303
     * @return Mock
304
     */
305
    public function shouldAllowMockingProtectedMethods()
306
    {
307
        $this->_mockery_allowMockingProtectedMethods = true;
308
        return $this;
309
    }
310
311
312
    /**
313
     * Set mock to defer unexpected methods to it's parent
314
     *
315
     * This is particularly useless for this class, as it doesn't have a parent,
316
     * but included for completeness
317
     *
318
     * @return Mock
319
     */
320
    public function shouldDeferMissing()
321
    {
322
        $this->_mockery_deferMissing = true;
323
        return $this;
324
    }
325
326
    /**
327
     * Create an obviously worded alias to shouldDeferMissing()
328
     *
329
     * @return Mock
330
     */
331
    public function makePartial()
332
    {
333
        return $this->shouldDeferMissing();
334
    }
335
336
    /**
337
     * In the event shouldReceive() accepting one or more methods/returns,
338
     * this method will switch them from normal expectations to default
339
     * expectations
340
     *
341
     * @return self
342
     */
343
    public function byDefault()
344
    {
345
        foreach ($this->_mockery_expectations as $director) {
346
            $exps = $director->getExpectations();
347
            foreach ($exps as $exp) {
348
                $exp->byDefault();
349
            }
350
        }
351
        return $this;
352
    }
353
354
    /**
355
     * Capture calls to this mock
356
     */
357
    public function __call($method, array $args)
358
    {
359
        return $this->_mockery_handleMethodCall($method, $args);
360
    }
361
362
    public static function __callStatic($method, array $args)
363
    {
364
        return self::_mockery_handleStaticMethodCall($method, $args);
365
    }
366
367
    /**
368
     * Forward calls to this magic method to the __call method
369
     */
370
    public function __toString()
371
    {
372
        return $this->__call('__toString', array());
373
    }
374
375
    /**
376
     * Iterate across all expectation directors and validate each
377
     *
378
     * @throws \Mockery\CountValidator\Exception
379
     * @return void
380
     */
381
    public function mockery_verify()
382
    {
383
        if ($this->_mockery_verified) {
384
            return;
385
        }
386
        if (isset($this->_mockery_ignoreVerification)
387
            && $this->_mockery_ignoreVerification == true) {
388
            return;
389
        }
390
        $this->_mockery_verified = true;
391
        foreach ($this->_mockery_expectations as $director) {
392
            $director->verify();
393
        }
394
    }
395
396
    /**
397
     * Tear down tasks for this mock
398
     *
399
     * @return void
400
     */
401
    public function mockery_teardown()
402
    {
403
    }
404
405
    /**
406
     * Fetch the next available allocation order number
407
     *
408
     * @return int
409
     */
410
    public function mockery_allocateOrder()
411
    {
412
        $this->_mockery_allocatedOrder += 1;
413
        return $this->_mockery_allocatedOrder;
414
    }
415
416
    /**
417
     * Set ordering for a group
418
     *
419
     * @param mixed $group
420
     * @param int $order
421
     */
422
    public function mockery_setGroup($group, $order)
423
    {
424
        $this->_mockery_groups[$group] = $order;
425
    }
426
427
    /**
428
     * Fetch array of ordered groups
429
     *
430
     * @return array
431
     */
432
    public function mockery_getGroups()
433
    {
434
        return $this->_mockery_groups;
435
    }
436
437
    /**
438
     * Set current ordered number
439
     *
440
     * @param int $order
441
     */
442
    public function mockery_setCurrentOrder($order)
443
    {
444
        $this->_mockery_currentOrder = $order;
445
        return $this->_mockery_currentOrder;
446
    }
447
448
    /**
449
     * Get current ordered number
450
     *
451
     * @return int
452
     */
453
    public function mockery_getCurrentOrder()
454
    {
455
        return $this->_mockery_currentOrder;
456
    }
457
458
    /**
459
     * Validate the current mock's ordering
460
     *
461
     * @param string $method
462
     * @param int $order
463
     * @throws \Mockery\Exception
464
     * @return void
465
     */
466
    public function mockery_validateOrder($method, $order)
467
    {
468
        if ($order < $this->_mockery_currentOrder) {
469
            $exception = new \Mockery\Exception\InvalidOrderException(
470
                'Method ' . __CLASS__ . '::' . $method . '()'
471
                . ' called out of order: expected order '
472
                . $order . ', was ' . $this->_mockery_currentOrder
473
            );
474
            $exception->setMock($this)
475
                ->setMethodName($method)
476
                ->setExpectedOrder($order)
477
                ->setActualOrder($this->_mockery_currentOrder);
478
            throw $exception;
479
        }
480
        $this->mockery_setCurrentOrder($order);
481
    }
482
483
    /**
484
     * Gets the count of expectations for this mock
485
     *
486
     * @return int
487
     */
488
    public function mockery_getExpectationCount()
489
    {
490
        $count = $this->_mockery_expectations_count;
491
        foreach ($this->_mockery_expectations as $director) {
492
            $count += $director->getExpectationCount();
493
        }
494
        return $count;
495
    }
496
497
    /**
498
     * Return the expectations director for the given method
499
     *
500
     * @var string $method
501
     * @return \Mockery\ExpectationDirector|null
502
     */
503
    public function mockery_setExpectationsFor($method, \Mockery\ExpectationDirector $director)
504
    {
505
        $this->_mockery_expectations[$method] = $director;
506
    }
507
508
    /**
509
     * Return the expectations director for the given method
510
     *
511
     * @var string $method
512
     * @return \Mockery\ExpectationDirector|null
513
     */
514
    public function mockery_getExpectationsFor($method)
515
    {
516
        if (isset($this->_mockery_expectations[$method])) {
517
            return $this->_mockery_expectations[$method];
518
        }
519
    }
520
521
    /**
522
     * Find an expectation matching the given method and arguments
523
     *
524
     * @var string $method
525
     * @var array $args
526
     * @return \Mockery\Expectation|null
527
     */
528
    public function mockery_findExpectation($method, array $args)
529
    {
530
        if (!isset($this->_mockery_expectations[$method])) {
531
            return null;
532
        }
533
        $director = $this->_mockery_expectations[$method];
534
535
        return $director->findExpectation($args);
536
    }
537
538
    /**
539
     * Return the container for this mock
540
     *
541
     * @return \Mockery\Container
542
     */
543
    public function mockery_getContainer()
544
    {
545
        return $this->_mockery_container;
546
    }
547
548
    /**
549
     * Return the name for this mock
550
     *
551
     * @return string
552
     */
553
    public function mockery_getName()
554
    {
555
        return __CLASS__;
556
    }
557
558
    /**
559
     * @return array
560
     */
561
    public function mockery_getMockableProperties()
562
    {
563
        return $this->_mockery_mockableProperties;
564
    }
565
566
    public function __isset($name)
567
    {
568
        if (false === stripos($name, '_mockery_') && method_exists(get_parent_class($this), '__isset')) {
569
            return parent::__isset($name);
570
        }
571
572
        return false;
573
    }
574
575
    public function mockery_getExpectations()
576
    {
577
        return $this->_mockery_expectations;
578
    }
579
580
    /**
581
     * Calls a parent class method and returns the result. Used in a passthru
582
     * expectation where a real return value is required while still taking
583
     * advantage of expectation matching and call count verification.
584
     *
585
     * @param string $name
586
     * @param array $args
587
     * @return mixed
588
     */
589
    public function mockery_callSubjectMethod($name, array $args)
590
    {
591
        return call_user_func_array('parent::' . $name, $args);
592
    }
593
594
    /**
595
     * @return string[]
596
     */
597
    public function mockery_getMockableMethods()
598
    {
599
        return $this->_mockery_mockableMethods;
600
    }
601
602
    /**
603
     * @return bool
604
     */
605
    public function mockery_isAnonymous()
606
    {
607
        $rfc = new \ReflectionClass($this);
608
        
609
        // HHVM has a Stringish interface
610
        $interfaces = array_filter($rfc->getInterfaces(), function ($i) {
611
            return $i->getName() !== "Stringish";
612
        });
613
        $onlyImplementsMock = 1 == count($interfaces);
614
615
        return (false === $rfc->getParentClass()) && $onlyImplementsMock;
616
    }
617
618
    public function __wakeup()
619
    {
620
        /**
621
         * This does not add __wakeup method support. It's a blind method and any
622
         * expected __wakeup work will NOT be performed. It merely cuts off
623
         * annoying errors where a __wakeup exists but is not essential when
624
         * mocking
625
         */
626
    }
627
628
    public function __destruct()
629
    {
630
        /**
631
         * Overrides real class destructor in case if class was created without original constructor
632
         */
633
    }
634
635
    public function mockery_getMethod($name)
636
    {
637
        foreach ($this->mockery_getMethods() as $method) {
638
            if ($method->getName() == $name) {
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
639
                return $method;
640
            }
641
        }
642
643
        return null;
644
    }
645
646
    /**
647
     * @param string $name Method name.
648
     *
649
     * @return mixed Generated return value based on the declared return value of the named method.
650
     */
651
    public function mockery_returnValueForMethod($name)
652
    {
653
        if (version_compare(PHP_VERSION, '7.0.0-dev') < 0) {
654
            return;
655
        }
656
657
        $rm = $this->mockery_getMethod($name);
658
        if (!$rm || !$rm->hasReturnType()) {
659
            return;
660
        }
661
662
        $type = (string) $rm->getReturnType();
663
        switch ($type) {
664
            case '':       return;
665
            case 'string': return '';
666
            case 'int':    return 0;
667
            case 'float':  return 0.0;
668
            case 'bool':   return false;
669
            case 'array':  return [];
670
671
            case 'callable':
672
            case 'Closure':
673
                return function () {
674
                };
675
676
            case 'Traversable':
677
            case 'Generator':
678
                // Remove eval() when minimum version >=5.5
679
                $generator = eval('return function () { yield; };');
680
                return $generator();
681
682
            case 'self':
683
                return \Mockery::mock($rm->getDeclaringClass()->getName());
0 ignored issues
show
introduced by
Consider using $rm->class. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
684
685
            case 'void':
686
                return null;
687
688
            default:
689
                return \Mockery::mock($type);
690
        }
691
    }
692
693
    public function shouldHaveReceived($method = null, $args = null)
694
    {
695
        if ($method === null) {
696
            return new HigherOrderMessage($this, "shouldHaveReceived");
697
        }
698
699
        $expectation = new \Mockery\VerificationExpectation($this, $method);
700
        if (null !== $args) {
701
            $expectation->withArgs($args);
0 ignored issues
show
Documentation introduced by
$args is of type null, but the function expects a array|object<Closure>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
702
        }
703
        $expectation->atLeast()->once();
704
        $director = new \Mockery\VerificationDirector($this->_mockery_getReceivedMethodCalls(), $expectation);
705
        $this->_mockery_expectations_count++;
706
        $director->verify();
707
        return $director;
708
    }
709
710
    public function shouldNotHaveReceived($method = null, $args = null)
711
    {
712
        if ($method === null) {
713
            return new HigherOrderMessage($this, "shouldNotHaveReceived");
714
        }
715
716
        $expectation = new \Mockery\VerificationExpectation($this, $method);
717
        if (null !== $args) {
718
            $expectation->withArgs($args);
0 ignored issues
show
Documentation introduced by
$args is of type null, but the function expects a array|object<Closure>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
719
        }
720
        $expectation->never();
721
        $director = new \Mockery\VerificationDirector($this->_mockery_getReceivedMethodCalls(), $expectation);
722
        $this->_mockery_expectations_count++;
723
        $director->verify();
724
        return null;
725
    }
726
727
    protected static function _mockery_handleStaticMethodCall($method, array $args)
728
    {
729
        try {
730
            $associatedRealObject = \Mockery::fetchMock(__CLASS__);
731
            return $associatedRealObject->__call($method, $args);
732
        } catch (\BadMethodCallException $e) {
733
            throw new \BadMethodCallException(
734
                'Static method ' . $associatedRealObject->mockery_getName() . '::' . $method
735
                . '() does not exist on this mock object'
736
            );
737
        }
738
    }
739
740
    protected function _mockery_getReceivedMethodCalls()
741
    {
742
        return $this->_mockery_receivedMethodCalls ?: $this->_mockery_receivedMethodCalls = new \Mockery\ReceivedMethodCalls();
743
    }
744
745
    protected function _mockery_handleMethodCall($method, array $args)
746
    {
747
        $this->_mockery_getReceivedMethodCalls()->push(new \Mockery\MethodCall($method, $args));
748
749
        $rm = $this->mockery_getMethod($method);
750
        if ($rm && $rm->isProtected() && !$this->_mockery_allowMockingProtectedMethods) {
751
            if ($rm->isAbstract()) {
752
                return;
753
            }
754
755
            try {
756
                $prototype = $rm->getPrototype();
757
                if ($prototype->isAbstract()) {
758
                    return;
759
                }
760
            } catch (\ReflectionException $re) {
761
                // noop - there is no hasPrototype method
762
            }
763
764
            return call_user_func_array("parent::$method", $args);
765
        }
766
767
        if (isset($this->_mockery_expectations[$method])
768
        && !$this->_mockery_disableExpectationMatching) {
769
            $handler = $this->_mockery_expectations[$method];
770
771
            try {
772
                return $handler->call($args);
773
            } catch (\Mockery\Exception\NoMatchingExpectationException $e) {
774
                if (!$this->_mockery_ignoreMissing && !$this->_mockery_deferMissing) {
775
                    throw $e;
776
                }
777
            }
778
        }
779
780
        if (!is_null($this->_mockery_partial) && method_exists($this->_mockery_partial, $method)) {
781
            return call_user_func_array(array($this->_mockery_partial, $method), $args);
782
        } elseif ($this->_mockery_deferMissing && is_callable("parent::$method")
783
            && (!$this->hasMethodOverloadingInParentClass() || method_exists(get_parent_class($this), $method))) {
784
            return call_user_func_array("parent::$method", $args);
785
        } elseif ($method == '__toString') {
786
            // __toString is special because we force its addition to the class API regardless of the
787
            // original implementation.  Thus, we should always return a string rather than honor
788
            // _mockery_ignoreMissing and break the API with an error.
789
            return sprintf("%s#%s", __CLASS__, spl_object_hash($this));
790
        } elseif ($this->_mockery_ignoreMissing) {
791
            if (\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed() || (method_exists($this->_mockery_partial, $method) || is_callable("parent::$method"))) {
792
                if ($this->_mockery_defaultReturnValue instanceof \Mockery\Undefined) {
793
                    return call_user_func_array(array($this->_mockery_defaultReturnValue, $method), $args);
794
                } elseif (null === $this->_mockery_defaultReturnValue) {
795
                    return $this->mockery_returnValueForMethod($method);
796
                } else {
797
                    return $this->_mockery_defaultReturnValue;
798
                }
799
            }
800
        }
801
802
        $message = 'Method ' . __CLASS__ . '::' . $method .
803
            '() does not exist on this mock object';
804
805
        if (!is_null($rm)) {
806
            $message = 'Received ' . __CLASS__ .
807
                '::' . $method . '(), but no expectations were specified';
808
        }
809
810
        throw new \BadMethodCallException(
811
            $message
812
        );
813
    }
814
815
    /**
816
     * Uses reflection to get the list of all
817
     * methods within the current mock object
818
     *
819
     * @return array
820
     */
821
    protected function mockery_getMethods()
822
    {
823
        if (static::$_mockery_methods) {
0 ignored issues
show
Bug Best Practice introduced by
The expression static::$_mockery_methods of type ReflectionMethod[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
824
            return static::$_mockery_methods;
825
        }
826
827
        if (isset($this->_mockery_partial)) {
828
            $reflected = new \ReflectionObject($this->_mockery_partial);
829
        } else {
830
            $reflected = new \ReflectionClass($this);
831
        }
832
833
        return static::$_mockery_methods = $reflected->getMethods();
834
    }
835
836
    private function hasMethodOverloadingInParentClass()
837
    {
838
        // if there's __call any name would be callable
839
        return is_callable('parent::aFunctionNameThatNoOneWouldEverUseInRealLife12345');
840
    }
841
842
    /**
843
     * @return array
844
     */
845
    private function getNonPublicMethods()
846
    {
847
        return array_map(
848
            function ($method) {
849
                return $method->getName();
850
            },
851
            array_filter($this->mockery_getMethods(), function ($method) {
852
                return !$method->isPublic();
853
            })
854
        );
855
    }
856
}
857