Completed
Push — master ( ebad32...ea44b8 )
by Dave
02:43
created

Mockery::on()   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 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
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 Pádraic Brady (http://blog.astrumfutura.com)
18
 * @license    http://github.com/padraic/mockery/blob/master/LICENSE New BSD License
19
 */
20
21
use Mockery\ExpectationInterface;
22
use Mockery\Generator\CachingGenerator;
23
use Mockery\Generator\Generator;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Generator.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
24
use Mockery\Generator\MockConfigurationBuilder;
25
use Mockery\Generator\StringManipulationGenerator;
26
use Mockery\Loader\EvalLoader;
27
use Mockery\Loader\Loader;
28
29
class Mockery
30
{
31
    const BLOCKS = 'Mockery_Forward_Blocks';
32
33
    /**
34
     * Global container to hold all mocks for the current unit test running.
35
     *
36
     * @var \Mockery\Container
37
     */
38
    protected static $_container = null;
39
40
    /**
41
     * Global configuration handler containing configuration options.
42
     *
43
     * @var \Mockery\Configuration
44
     */
45
    protected static $_config = null;
46
47
    /**
48
     * @var \Mockery\Generator\Generator
49
     */
50
    protected static $_generator;
51
52
    /**
53
     * @var \Mockery\Loader\Loader
54
     */
55
    protected static $_loader;
56
57
    /**
58
     * @var array
59
     */
60
    private static $_filesToCleanUp = [];
61
62
    /**
63
     * Defines the global helper functions
64
     * 
65
     * @return void
66
     */
67 3
    public static function globalHelpers()
68
    {
69 3
        require_once __DIR__.'/helpers.php';
70 3
    }
71
72
    /**
73
     * Static shortcut to \Mockery\Container::mock().
74
     *
75
     * @param array $args
76
     *
77
     * @return \Mockery\MockInterface
78
     */
79 37
    public static function mock(...$args)
80
    {
81 37
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
82
    }
83
84
    /**
85
     * Static and semantic shortcut for getting a mock from the container
86
     * and applying the spy's expected behavior into it.
87
     *
88
     * @param array $args
89
     *
90
     * @return \Mockery\MockInterface
91
     */
92 9
    public static function spy(...$args)
93
    {
94 9
        return call_user_func_array(array(self::getContainer(), 'mock'), $args)->shouldIgnoreMissing();
95
    }
96
97
    /**
98
     * Static and Semantic shortcut to \Mockery\Container::mock().
99
     *
100
     * @param array $args
101
     *
102
     * @return \Mockery\MockInterface
103
     */
104
    public static function instanceMock(...$args)
105
    {
106
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
107
    }
108
109
    /**
110
     * Static shortcut to \Mockery\Container::mock(), first argument names the mock.
111
     *
112
     * @param array $args
113
     *
114
     * @return \Mockery\MockInterface
115
     */
116 5
    public static function namedMock(...$args)
117
    {
118 5
        $name = array_shift($args);
119
120 5
        $builder = new MockConfigurationBuilder();
121 5
        $builder->setName($name);
122
123 5
        array_unshift($args, $builder);
124
125 5
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
126
    }
127
128
    /**
129
     * Static shortcut to \Mockery\Container::self().
130
     *
131
     * @throws LogicException
132
     *
133
     * @return \Mockery\MockInterface
134
     */
135 2
    public static function self()
136
    {
137 2
        if (is_null(self::$_container)) {
138 1
            throw new \LogicException('You have not declared any mocks yet');
139
        }
140
141 1
        return self::$_container->self();
142
    }
143
144
    /**
145
     * Static shortcut to closing up and verifying all mocks in the global
146
     * container, and resetting the container static variable to null.
147
     *
148
     * @return void
149
     */
150 413
    public static function close()
151
    {
152 413
        foreach (self::$_filesToCleanUp as $fileName) {
153 18
            @unlink($fileName);
154 413
        }
155 413
        self::$_filesToCleanUp = [];
156
157 413
        if (is_null(self::$_container)) {
158
            return;
159
        }
160
161 413
        self::$_container->mockery_teardown();
162 411
        self::$_container->mockery_close();
163 411
        self::$_container = null;
164 411
    }
165
166
    /**
167
     * Static fetching of a mock associated with a name or explicit class poser.
168
     *
169
     * @param $name
170
     *
171
     * @return \Mockery\Mock
172
     */
173 11
    public static function fetchMock($name)
174
    {
175 11
        return self::$_container->fetchMock($name);
176
    }
177
178
    /**
179
     * Lazy loader and getter for
180
     * the container property.
181
     *
182
     * @return Mockery\Container
183
     */
184 437
    public static function getContainer()
185
    {
186 437
        if (is_null(self::$_container)) {
187 406
            self::$_container = new Mockery\Container(self::getGenerator(), self::getLoader());
188 406
        }
189
190 437
        return self::$_container;
191
    }
192
193
    /**
194
     * Setter for the $_generator static propery.
195
     *
196
     * @param \Mockery\Generator\Generator $generator
197
     */
198
    public static function setGenerator(Generator $generator)
199
    {
200
        self::$_generator = $generator;
201
    }
202
203
    /**
204
     * Lazy loader method and getter for
205
     * the generator property.
206
     *
207
     * @return Generator
208
     */
209 406
    public static function getGenerator()
210
    {
211 406
        if (is_null(self::$_generator)) {
212 1
            self::$_generator = self::getDefaultGenerator();
213 1
        }
214
215 406
        return self::$_generator;
216
    }
217
218
    /**
219
     * Creates and returns a default generator
220
     * used inside this class.
221
     *
222
     * @return CachingGenerator
223
     */
224 399
    public static function getDefaultGenerator()
225
    {
226 399
        return new CachingGenerator(StringManipulationGenerator::withDefaultPasses());
227
    }
228
229
    /**
230
     * Setter for the $_loader static property.
231
     *
232
     * @param Loader $loader
233
     */
234
    public static function setLoader(Loader $loader)
235
    {
236
        self::$_loader = $loader;
237
    }
238
239
    /**
240
     * Lazy loader method and getter for
241
     * the $_loader property.
242
     *
243
     * @return Loader
244
     */
245 406
    public static function getLoader()
246
    {
247 406
        if (is_null(self::$_loader)) {
248 1
            self::$_loader = self::getDefaultLoader();
249 1
        }
250
251 406
        return self::$_loader;
252
    }
253
254
    /**
255
     * Gets an EvalLoader to be used as default.
256
     *
257
     * @return EvalLoader
258
     */
259 273
    public static function getDefaultLoader()
260
    {
261 273
        return new EvalLoader();
262
    }
263
264
    /**
265
     * Set the container.
266
     *
267
     * @param \Mockery\Container $container
268
     *
269
     * @return \Mockery\Container
270
     */
271 18
    public static function setContainer(Mockery\Container $container)
272
    {
273 18
        return self::$_container = $container;
274
    }
275
276
    /**
277
     * Reset the container to null.
278
     *
279
     * @return void
280
     */
281 15
    public static function resetContainer()
282
    {
283 15
        self::$_container = null;
284 15
    }
285
286
    /**
287
     * Return instance of ANY matcher.
288
     *
289
     * @return \Mockery\Matcher\Any
290
     */
291 5
    public static function any()
292
    {
293 5
        return new \Mockery\Matcher\Any();
294
    }
295
296
    /**
297
     * Return instance of TYPE matcher.
298
     *
299
     * @param $expected
300
     *
301
     * @return \Mockery\Matcher\Type
302
     */
303 48
    public static function type($expected)
304
    {
305 48
        return new \Mockery\Matcher\Type($expected);
306
    }
307
308
    /**
309
     * Return instance of DUCKTYPE matcher.
310
     *
311
     * @param array $args
312
     *
313
     * @return \Mockery\Matcher\Ducktype
314
     */
315 3
    public static function ducktype(...$args)
316
    {
317 3
        return new \Mockery\Matcher\Ducktype($args);
318
    }
319
320
    /**
321
     * Return instance of SUBSET matcher.
322
     *
323
     * @param array $part
324
     * @param bool $strict - (Optional) True for strict comparison, false for loose
325
     *
326
     * @return \Mockery\Matcher\Subset
327
     */
328 3
    public static function subset(array $part, $strict = true)
329
    {
330 3
        return new \Mockery\Matcher\Subset($part, $strict);
331
    }
332
333
    /**
334
     * Return instance of CONTAINS matcher.
335
     *
336
     * @param array $args
337
     *
338
     * @return \Mockery\Matcher\Contains
339
     */
340 3
    public static function contains(...$args)
341
    {
342 3
        return new \Mockery\Matcher\Contains($args);
343
    }
344
345
    /**
346
     * Return instance of HASKEY matcher.
347
     *
348
     * @param $key
349
     *
350
     * @return \Mockery\Matcher\HasKey
351
     */
352 3
    public static function hasKey($key)
353
    {
354 3
        return new \Mockery\Matcher\HasKey($key);
355
    }
356
357
    /**
358
     * Return instance of HASVALUE matcher.
359
     *
360
     * @param $val
361
     *
362
     * @return \Mockery\Matcher\HasValue
363
     */
364 3
    public static function hasValue($val)
365
    {
366 3
        return new \Mockery\Matcher\HasValue($val);
367
    }
368
369
    /**
370
     * Return instance of CLOSURE matcher.
371
     *
372
     * @param $closure
373
     *
374
     * @return \Mockery\Matcher\Closure
375
     */
376 7
    public static function on($closure)
377
    {
378 7
        return new \Mockery\Matcher\Closure($closure);
379
    }
380
381
    /**
382
     * Return instance of MUSTBE matcher.
383
     *
384
     * @param $expected
385
     *
386
     * @return \Mockery\Matcher\MustBe
387
     */
388 6
    public static function mustBe($expected)
389
    {
390 6
        return new \Mockery\Matcher\MustBe($expected);
0 ignored issues
show
Deprecated Code introduced by
The class Mockery\Matcher\MustBe has been deprecated with message: 2.0 Due to ambiguity, use Hamcrest or PHPUnit equivalents

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
391
    }
392
393
    /**
394
     * Return instance of NOT matcher.
395
     *
396
     * @param $expected
397
     *
398
     * @return \Mockery\Matcher\Not
399
     */
400 3
    public static function not($expected)
401
    {
402 3
        return new \Mockery\Matcher\Not($expected);
403
    }
404
405
    /**
406
     * Return instance of ANYOF matcher.
407
     *
408
     * @param array $args
409
     *
410
     * @return \Mockery\Matcher\AnyOf
411
     */
412 3
    public static function anyOf(...$args)
413
    {
414 3
        return new \Mockery\Matcher\AnyOf($args);
415
    }
416
417
    /**
418
     * Return instance of NOTANYOF matcher.
419
     *
420
     * @param array $args
421
     *
422
     * @return \Mockery\Matcher\NotAnyOf
423
     */
424 3
    public static function notAnyOf(...$args)
425
    {
426 3
        return new \Mockery\Matcher\NotAnyOf($args);
427
    }
428
429
    /**
430
     * Lazy loader and Getter for the global
431
     * configuration container.
432
     *
433
     * @return \Mockery\Configuration
434
     */
435 425
    public static function getConfiguration()
436
    {
437 425
        if (is_null(self::$_config)) {
438 1
            self::$_config = new \Mockery\Configuration();
439 1
        }
440
441 425
        return self::$_config;
442
    }
443
444
    /**
445
     * Utility method to format method name and arguments into a string.
446
     *
447
     * @param string $method
448
     * @param array $arguments
449
     *
450
     * @return string
451
     */
452 92
    public static function formatArgs($method, array $arguments = null)
453
    {
454 92
        if (is_null($arguments)) {
455
            return $method . '()';
456
        }
457
458 92
        $formattedArguments = array();
459 92
        foreach ($arguments as $argument) {
460 91
            $formattedArguments[] = self::formatArgument($argument);
461 92
        }
462
463 92
        return $method . '(' . implode(', ', $formattedArguments) . ')';
464
    }
465
466
    /**
467
     * Gets the string representation
468
     * of any passed argument.
469
     *
470
     * @param $argument
471
     * @param $depth
472
     *
473
     * @return string
474
     */
475 91
    private static function formatArgument($argument, $depth = 0)
476
    {
477 91
        if (is_object($argument)) {
478 41
            return 'object(' . get_class($argument) . ')';
479
        }
480
481 54
        if (is_int($argument) || is_float($argument)) {
482 37
            return $argument;
483
        }
484
485 26
        if (is_array($argument)) {
486 13
            if ($depth === 1) {
487 2
                $argument = '[...]';
488 2
            } else {
489 13
                $sample = array();
490 13
                foreach ($argument as $key => $value) {
491 12
                    $key = is_int($key) ? $key : "'$key'";
492 12
                    $value = self::formatArgument($value, $depth + 1);
493 12
                    $sample[] = "$key => $value";
494 13
                }
495
496 13
                $argument = "[".implode(", ", $sample)."]";
497
            }
498
499 13
            return ((strlen($argument) > 1000) ? substr($argument, 0, 1000).'...]' : $argument);
500
        }
501
502 17
        if (is_bool($argument)) {
503 1
            return $argument ? 'true' : 'false';
504
        }
505
506 16
        if (is_resource($argument)) {
507 2
            return 'resource(...)';
508
        }
509
510 14
        if (is_null($argument)) {
511 1
            return 'NULL';
512
        }
513
514 13
        return "'".(string) $argument."'";
515
    }
516
517
    /**
518
     * Utility function to format objects to printable arrays.
519
     *
520
     * @param array $objects
521
     *
522
     * @return string
523
     */
524 52
    public static function formatObjects(array $objects = null)
525
    {
526 52
        static $formatting;
527
528 52
        if ($formatting) {
529 1
            return '[Recursion]';
530
        }
531
532 52
        if (is_null($objects)) {
533
            return '';
534
        }
535
536 52
        $objects = array_filter($objects, 'is_object');
537 52
        if (empty($objects)) {
538 45
            return '';
539
        }
540
541 7
        $formatting = true;
542 7
        $parts = array();
543
544 7
        foreach ($objects as $object) {
545 7
            $parts[get_class($object)] = self::objectToArray($object);
546 7
        }
547
548 7
        $formatting = false;
549
550 7
        return 'Objects: ( ' . var_export($parts, true) . ')';
551
    }
552
553
    /**
554
     * Utility function to turn public properties and public get* and is* method values into an array.
555
     *
556
     * @param     $object
557
     * @param int $nesting
558
     *
559
     * @return array
560
     */
561 7
    private static function objectToArray($object, $nesting = 3)
562
    {
563 7
        if ($nesting == 0) {
564
            return array('...');
565
        }
566
567
        return array(
568 7
            'class' => get_class($object),
569 7
            'properties' => self::extractInstancePublicProperties($object, $nesting),
570 7
            'getters' => self::extractGetters($object, $nesting)
571 7
        );
572
    }
573
574
    /**
575
     * Returns all public instance properties.
576
     *
577
     * @param $object
578
     * @param $nesting
579
     *
580
     * @return array
581
     */
582 7
    private static function extractInstancePublicProperties($object, $nesting)
583
    {
584 7
        $reflection = new \ReflectionClass(get_class($object));
585 7
        $properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC);
586 7
        $cleanedProperties = array();
587
588 7
        foreach ($properties as $publicProperty) {
589 1
            if (!$publicProperty->isStatic()) {
590
                $name = $publicProperty->getName();
591
                $cleanedProperties[$name] = self::cleanupNesting($object->$name, $nesting);
592
            }
593 7
        }
594
595 7
        return $cleanedProperties;
596
    }
597
598
    /**
599
     * Returns all object getters.
600
     *
601
     * @param $object
602
     * @param $nesting
603
     *
604
     * @return array
605
     */
606 7
    private static function extractGetters($object, $nesting)
607
    {
608 7
        $reflection = new \ReflectionClass(get_class($object));
609 7
        $publicMethods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
610 7
        $getters = array();
611
612 7
        foreach ($publicMethods as $publicMethod) {
613 5
            $name = $publicMethod->getName();
0 ignored issues
show
Bug introduced by
Consider using $publicMethod->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
614 5
            $irrelevantName = (substr($name, 0, 3) !== 'get' && substr($name, 0, 2) !== 'is');
615 5
            $isStatic = $publicMethod->isStatic();
616 5
            $numberOfParameters = $publicMethod->getNumberOfParameters();
617
618 5
            if ($irrelevantName || $numberOfParameters != 0 || $isStatic) {
619 5
                continue;
620
            }
621
622
            try {
623 2
                $getters[$name] = self::cleanupNesting($object->$name(), $nesting);
624 2
            } catch (\Exception $e) {
625 1
                $getters[$name] = '!! ' . get_class($e) . ': ' . $e->getMessage() . ' !!';
626
            }
627 7
        }
628
629 7
        return $getters;
630
    }
631
632
    /**
633
     * Utility method used for recursively generating
634
     * an object or array representation.
635
     *
636
     * @param $argument
637
     * @param $nesting
638
     *
639
     * @return mixed
640
     */
641 1
    private static function cleanupNesting($argument, $nesting)
642
    {
643 1
        if (is_object($argument)) {
644
            $object = self::objectToArray($argument, $nesting - 1);
645
            $object['class'] = get_class($argument);
646
647
            return $object;
648
        }
649
650 1
        if (is_array($argument)) {
651 1
            return self::cleanupArray($argument, $nesting - 1);
652
        }
653
654 1
        return $argument;
655
    }
656
657
    /**
658
     * Utility method for recursively
659
     * gerating a representation
660
     * of the given array.
661
     *
662
     * @param array $argument
663
     * @param int $nesting
664
     *
665
     * @return mixed
666
     */
667 1
    private static function cleanupArray($argument, $nesting = 3)
668
    {
669 1
        if ($nesting == 0) {
670 1
            return '...';
671
        }
672
673 1
        foreach ($argument as $key => $value) {
674 1
            if (is_array($value)) {
675 1
                $argument[$key] = self::cleanupArray($value, $nesting - 1);
676 1
            } elseif (is_object($value)) {
677
                $argument[$key] = self::objectToArray($value, $nesting - 1);
678
            }
679 1
        }
680
681 1
        return $argument;
682
    }
683
684
    /**
685
     * Utility function to parse shouldReceive() arguments and generate
686
     * expectations from such as needed.
687
     *
688
     * @param Mockery\MockInterface $mock
689
     * @param array $args
690
     * @param callable $add
691
     * @return \Mockery\CompositeExpectation
692
     */
693 307
    public static function parseShouldReturnArgs(\Mockery\MockInterface $mock, $args, $add)
694
    {
695 307
        $composite = new \Mockery\CompositeExpectation();
696
697 307
        foreach ($args as $arg) {
698 307
            if (is_array($arg)) {
699 18
                foreach ($arg as $k => $v) {
700 18
                    $expectation = self::buildDemeterChain($mock, $k, $add)->andReturn($v);
0 ignored issues
show
Unused Code introduced by
The call to ExpectationInterface::andReturn() has too many arguments starting with $v.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
701 18
                    $composite->add($expectation);
0 ignored issues
show
Documentation introduced by
$expectation is of type object<Mockery\ExpectationInterface>, but the function expects a object<Mockery\Expectati...y\CompositeExpectation>.

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 18
                }
703 307
            } elseif (is_string($arg)) {
704 293
                $expectation = self::buildDemeterChain($mock, $arg, $add);
705 287
                $composite->add($expectation);
0 ignored issues
show
Documentation introduced by
$expectation is of type object<Mockery\ExpectationInterface>, but the function expects a object<Mockery\Expectati...y\CompositeExpectation>.

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...
706 287
            }
707 301
        }
708
709 301
        return $composite;
710
    }
711
712
    /**
713
     * Sets up expectations on the members of the CompositeExpectation and
714
     * builds up any demeter chain that was passed to shouldReceive.
715
     *
716
     * @param \Mockery\MockInterface $mock
717
     * @param string $arg
718
     * @param callable $add
719
     * @throws Mockery\Exception
720
     * @return \Mockery\ExpectationInterface
721
     */
722 307
    protected static function buildDemeterChain(\Mockery\MockInterface $mock, $arg, $add)
723
    {
724
        /** @var Mockery\Container $container */
725 307
        $container = $mock->mockery_getContainer();
726 307
        $methodNames = explode('->', $arg);
727 307
        reset($methodNames);
728
729 307
        if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed()
730 307
            && !$mock->mockery_isAnonymous()
731 307
            && !in_array(current($methodNames), $mock->mockery_getMockableMethods())
732 307
        ) {
733 4
            throw new \Mockery\Exception(
734
                'Mockery\'s configuration currently forbids mocking the method '
735 4
                . current($methodNames) . ' as it does not exist on the class or object '
736 4
                . 'being mocked'
737 4
            );
738
        }
739
740
        /** @var ExpectationInterface|null $expectations */
741 303
        $expectations = null;
742
743
        /** @var Callable $nextExp */
744
        $nextExp = function ($method) use ($add) {
745 303
            return $add($method);
746 303
        };
747
748 303
        while (true) {
749 303
            $method = array_shift($methodNames);
750 303
            $expectations = $mock->mockery_getExpectationsFor($method);
751
752 303
            if (is_null($expectations) || self::noMoreElementsInChain($methodNames)) {
753 303
                $expectations = $nextExp($method);
754 301
                if (self::noMoreElementsInChain($methodNames)) {
755 301
                    break;
756
                }
757
758 11
                $mock = self::getNewDemeterMock($container, $method, $expectations);
759 11
            } else {
760 5
                $demeterMockKey = $container->getKeyOfDemeterMockFor($method);
761 5
                if ($demeterMockKey) {
762 5
                    $mock = self::getExistingDemeterMock($container, $demeterMockKey);
763 5
                }
764
            }
765
766 11
            $nextExp = function ($n) use ($mock) {
767 11
                return $mock->shouldReceive($n);
768 11
            };
769 11
        }
770
771 301
        return $expectations;
772
    }
773
774
    /**
775
     * Gets a new demeter configured
776
     * mock from the container.
777
     *
778
     * @param \Mockery\Container $container
779
     * @param string $method
780
     * @param Mockery\ExpectationInterface $exp
781
     *
782
     * @return \Mockery\Mock
783
     */
784 11
    private static function getNewDemeterMock(
785
        Mockery\Container $container,
786
        $method,
787
        Mockery\ExpectationInterface $exp
788
    ) {
789 11
        $mock = $container->mock('demeter_' . $method);
790 11
        $exp->andReturn($mock);
791
792 11
        return $mock;
793
    }
794
795
    /**
796
     * Gets an specific demeter mock from
797
     * the ones kept by the container.
798
     *
799
     * @param \Mockery\Container $container
800
     * @param string $demeterMockKey
801
     *
802
     * @return mixed
803
     */
804 5
    private static function getExistingDemeterMock(
805
        Mockery\Container $container,
806
        $demeterMockKey
807
    ) {
808 5
        $mocks = $container->getMocks();
809 5
        $mock = $mocks[$demeterMockKey];
810
811 5
        return $mock;
812
    }
813
814
    /**
815
     * Checks if the passed array representing a demeter
816
     * chain with the method names is empty.
817
     *
818
     * @param array $methodNames
819
     *
820
     * @return bool
821
     */
822 301
    private static function noMoreElementsInChain(array $methodNames)
823
    {
824 301
        return empty($methodNames);
825
    }
826
827 17
    public static function declareClass($fqn)
828
    {
829 17
        return static::declareType($fqn, "class");
0 ignored issues
show
Bug introduced by
Since declareType() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of declareType() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
830
    }
831
832 2
    public static function declareInterface($fqn)
833
    {
834 2
        return static::declareType($fqn, "interface");
0 ignored issues
show
Bug introduced by
Since declareType() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of declareType() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
835
    }
836
837 18
    private static function declareType($fqn, $type)
838
    {
839 18
        $targetCode = "<?php ";
840 18
        $shortName = $fqn;
841
842 18
        if (strpos($fqn, "\\")) {
843 4
            $parts = explode("\\", $fqn);
844
845 4
            $shortName = trim(array_pop($parts));
846 4
            $namespace = implode("\\", $parts);
847
848 4
            $targetCode.= "namespace $namespace;\n";
849 4
        }
850
851 18
        $targetCode.= "$type $shortName {} ";
852
853
        /*
854
         * We could eval here, but it doesn't play well with the way
855
         * PHPUnit tries to backup global state and the require definition
856
         * loader
857
         */
858 18
        $tmpfname = tempnam(sys_get_temp_dir(), "Mockery");
859 18
        file_put_contents($tmpfname, $targetCode);
860 18
        require $tmpfname;
861 18
        \Mockery::registerFileForCleanUp($tmpfname);
862 18
    }
863
864
    /**
865
     * Register a file to be deleted on tearDown.
866
     *
867
     * @param string $fileName
868
     */
869 18
    public static function registerFileForCleanUp($fileName)
870
    {
871 18
        self::$_filesToCleanUp[] = $fileName;
872 18
    }
873
}
874