Completed
Pull Request — master (#563)
by
unknown
02:18
created

Mockery::resetContainer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1
Metric Value
dl 0
loc 4
ccs 3
cts 3
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
use Mockery\ExpectationInterface;
22
use Mockery\Generator\CachingGenerator;
23
use Mockery\Generator\Generator;
24
use Mockery\Generator\MockConfigurationBuilder;
25
use Mockery\Generator\StringManipulation\Pass\RemoveDestructorPass;
26
use Mockery\Generator\StringManipulationGenerator;
27
use Mockery\Generator\StringManipulation\Pass\CallTypeHintPass;
28
use Mockery\Generator\StringManipulation\Pass\ClassNamePass;
29
use Mockery\Generator\StringManipulation\Pass\ClassPass;
30
use Mockery\Generator\StringManipulation\Pass\InstanceMockPass;
31
use Mockery\Generator\StringManipulation\Pass\InterfacePass;
32
use Mockery\Generator\StringManipulation\Pass\MethodDefinitionPass;
33
use Mockery\Generator\StringManipulation\Pass\RemoveBuiltinMethodsThatAreFinalPass;
34
use Mockery\Generator\StringManipulation\Pass\RemoveUnserializeForInternalSerializableClassesPass;
35
use Mockery\Loader\EvalLoader;
36
use Mockery\Loader\Loader;
37
38
class Mockery
39
{
40
    const BLOCKS = 'Mockery_Forward_Blocks';
41
42
    /**
43
     * Global container to hold all mocks for the current unit test running.
44
     *
45
     * @var \Mockery\Container
46
     */
47
    protected static $_container = null;
48
49
    /**
50
     * Global configuration handler containing configuration options.
51
     *
52
     * @var \Mockery\Configuration
53
     */
54
    protected static $_config = null;
55
56
    /**
57
     * @var \Mockery\Generator\Generator
58
     */
59
    protected static $_generator;
60
61
    /**
62
     * @var \Mockery\Loader\Loader
63
     */
64
    protected static $_loader;
65
66
    /**
67
     * @var array
68
     */
69
    private static $_filesToCleanUp = [];
70
71
    /**
72
     * Static shortcut to \Mockery\Container::mock().
73
     *
74
     * @return \Mockery\MockInterface
75
     */
76 24
    public static function mock()
77
    {
78 24
        $args = func_get_args();
79
80 24
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
81
    }
82
83
    /**
84
     * @return \Mockery\MockInterface
85
     */
86 7
    public static function spy()
87
    {
88 7
        $args = func_get_args();
89 7
        return call_user_func_array(array(self::getContainer(), 'mock'), $args)->shouldIgnoreMissing();
90
    }
91
92
    /**
93
     * @return \Mockery\MockInterface
94
     */
95
    public static function instanceMock()
96
    {
97
        $args = func_get_args();
98
99
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
100
    }
101
102
    /**
103
     * Static shortcut to \Mockery\Container::mock(), first argument names the mock.
104
     *
105
     * @return \Mockery\MockInterface
106
     */
107 4
    public static function namedMock()
108
    {
109 4
        $args = func_get_args();
110 4
        $name = array_shift($args);
111
112 4
        $builder = new MockConfigurationBuilder();
113 4
        $builder->setName($name);
114
115 4
        array_unshift($args, $builder);
116
117 4
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
118
    }
119
120
    /**
121
     * Static shortcut to \Mockery\Container::self().
122
     *
123
     * @throws LogicException
124
     *
125
     * @return \Mockery\MockInterface
126
     */
127
    public static function self()
128
    {
129
        if (is_null(self::$_container)) {
130
            throw new \LogicException('You have not declared any mocks yet');
131
        }
132
133
        return self::$_container->self();
134
    }
135
136
    /**
137
     * Static shortcut to closing up and verifying all mocks in the global
138
     * container, and resetting the container static variable to null.
139
     *
140
     * @return void
141
     */
142 403
    public static function close()
143
    {
144 403
        foreach (self::$_filesToCleanUp as $fileName) {
145 401
            @unlink($fileName);
146 403
        }
147
148 403
        if (is_null(self::$_container)) {
149
            return;
150
        }
151
152 403
        self::$_container->mockery_teardown();
153 403
        self::$_container->mockery_close();
154 403
        self::$_container = null;
155 403
    }
156
157
    /**
158
     * Static fetching of a mock associated with a name or explicit class poser.
159
     *
160
     * @param $name
161
     *
162
     * @return \Mockery\Mock
163
     */
164 11
    public static function fetchMock($name)
165
    {
166 11
        return self::$_container->fetchMock($name);
167
    }
168
169
    /**
170
     * Get the container.
171
     */
172 418
    public static function getContainer()
173
    {
174 418
        if (is_null(self::$_container)) {
175 412
            self::$_container = new Mockery\Container(self::getGenerator(), self::getLoader());
176 412
        }
177
178 418
        return self::$_container;
179
    }
180
181
    /**
182
     * @param \Mockery\Generator\Generator $generator
183
     */
184
    public static function setGenerator(Generator $generator)
185
    {
186
        self::$_generator = $generator;
187
    }
188
189 412
    public static function getGenerator()
190
    {
191 412
        if (is_null(self::$_generator)) {
192 1
            self::$_generator = self::getDefaultGenerator();
193 1
        }
194
195 412
        return self::$_generator;
196
    }
197
198 399
    public static function getDefaultGenerator()
199
    {
200 399
        $generator = new StringManipulationGenerator(array(
201 399
            new CallTypeHintPass(),
202 399
            new ClassPass(),
203 399
            new ClassNamePass(),
204 399
            new InstanceMockPass(),
205 399
            new InterfacePass(),
206 399
            new MethodDefinitionPass(),
207 399
            new RemoveUnserializeForInternalSerializableClassesPass(),
208 399
            new RemoveBuiltinMethodsThatAreFinalPass(),
209 399
            new RemoveDestructorPass(),
210 399
        ));
211
212 399
        return new CachingGenerator($generator);
213 1
    }
214
215
    /**
216
     * @param Loader $loader
217
     */
218
    public static function setLoader(Loader $loader)
219
    {
220
        self::$_loader = $loader;
221
    }
222
223
    /**
224
     * @return Loader
225
     */
226 412
    public static function getLoader()
227
    {
228 412
        if (is_null(self::$_loader)) {
229 1
            self::$_loader = self::getDefaultLoader();
230 1
        }
231
232 412
        return self::$_loader;
233
    }
234
235
    /**
236
     * @return EvalLoader
237
     */
238 273
    public static function getDefaultLoader()
239
    {
240 273
        return new EvalLoader();
241
    }
242
243
    /**
244
     * Set the container.
245
     *
246
     * @param \Mockery\Container $container
247
     *
248
     * @return \Mockery\Container
249
     */
250 18
    public static function setContainer(Mockery\Container $container)
251
    {
252 18
        return self::$_container = $container;
253
    }
254
255
    /**
256
     * Reset the container to null.
257
     */
258 15
    public static function resetContainer()
259
    {
260 15
        self::$_container = null;
261 15
    }
262
263
    /**
264
     * Return instance of ANY matcher.
265
     *
266
     * @return \Mockery\Matcher\Any
267
     */
268 5
    public static function any()
269
    {
270 5
        return new \Mockery\Matcher\Any();
271
    }
272
273
    /**
274
     * Return instance of TYPE matcher.
275
     *
276
     * @param $expected
277
     *
278
     * @return \Mockery\Matcher\Type
279
     */
280 48
    public static function type($expected)
281
    {
282 48
        return new \Mockery\Matcher\Type($expected);
283
    }
284
285
    /**
286
     * Return instance of DUCKTYPE matcher.
287
     *
288
     * @return \Mockery\Matcher\Ducktype
289
     */
290 3
    public static function ducktype()
291
    {
292 3
        return new \Mockery\Matcher\Ducktype(func_get_args());
293
    }
294
295
    /**
296
     * Return instance of SUBSET matcher.
297
     *
298
     * @param array $part
299
     *
300
     * @return \Mockery\Matcher\Subset
301
     */
302 3
    public static function subset(array $part)
303
    {
304 3
        return new \Mockery\Matcher\Subset($part);
305
    }
306
307
    /**
308
     * Return instance of CONTAINS matcher.
309
     *
310
     * @return \Mockery\Matcher\Contains
311
     */
312 3
    public static function contains()
313
    {
314 3
        return new \Mockery\Matcher\Contains(func_get_args());
315
    }
316
317
    /**
318
     * Return instance of HASKEY matcher.
319
     *
320
     * @param $key
321
     *
322
     * @return \Mockery\Matcher\HasKey
323
     */
324 3
    public static function hasKey($key)
325
    {
326 3
        return new \Mockery\Matcher\HasKey($key);
327
    }
328
329
    /**
330
     * Return instance of HASVALUE matcher.
331
     *
332
     * @param $val
333
     *
334
     * @return \Mockery\Matcher\HasValue
335
     */
336 3
    public static function hasValue($val)
337
    {
338 3
        return new \Mockery\Matcher\HasValue($val);
339
    }
340
341
    /**
342
     * Return instance of CLOSURE matcher.
343
     *
344
     * @param $closure
345
     *
346
     * @return \Mockery\Matcher\Closure
347
     */
348 7
    public static function on($closure)
349
    {
350 7
        return new \Mockery\Matcher\Closure($closure);
351
    }
352
353
    /**
354
     * Return instance of MUSTBE matcher.
355
     *
356
     * @param $expected
357
     *
358
     * @return \Mockery\Matcher\MustBe
359
     */
360 9
    public static function mustBe($expected)
361
    {
362 9
        return new \Mockery\Matcher\MustBe($expected);
363
    }
364
365
    /**
366
     * Return instance of NOT matcher.
367
     *
368
     * @param $expected
369
     *
370
     * @return \Mockery\Matcher\Not
371
     */
372 3
    public static function not($expected)
373
    {
374 3
        return new \Mockery\Matcher\Not($expected);
375
    }
376
377
    /**
378
     * Return instance of ANYOF matcher.
379
     *
380
     * @return \Mockery\Matcher\AnyOf
381
     */
382 3
    public static function anyOf()
383
    {
384 3
        return new \Mockery\Matcher\AnyOf(func_get_args());
385
    }
386
387
    /**
388
     * Return instance of NOTANYOF matcher.
389
     *
390
     * @return \Mockery\Matcher\NotAnyOf
391
     */
392 3
    public static function notAnyOf()
393
    {
394 3
        return new \Mockery\Matcher\NotAnyOf(func_get_args());
395
    }
396
397
    /**
398
     * Get the global configuration container.
399
     */
400 411
    public static function getConfiguration()
401
    {
402 411
        if (is_null(self::$_config)) {
403 1
            self::$_config = new \Mockery\Configuration();
404 1
        }
405
406 411
        return self::$_config;
407
    }
408
409
    /**
410
     * Utility method to format method name and arguments into a string.
411
     *
412
     * @param string $method
413
     * @param array $arguments
414
     *
415
     * @return string
416
     */
417 94
    public static function formatArgs($method, array $arguments = null)
418
    {
419 94
        if (is_null($arguments)) {
420 2
            return $method . '()';
421
        }
422
423 93
        $formattedArguments = array();
424 93
        foreach ($arguments as $argument) {
425 60
            $formattedArguments[] = self::formatArgument($argument);
426 93
        }
427
428 93
        return $method . '(' . implode(', ', $formattedArguments) . ')';
429
    }
430
431 60
    private static function formatArgument($argument, $depth = 0)
432
    {
433 60
        if (is_object($argument)) {
434 10
            return 'object(' . get_class($argument) . ')';
435
        }
436
437 54
        if (is_int($argument) || is_float($argument)) {
438 36
            return $argument;
439
        }
440
441 27
        if (is_array($argument)) {
442 13
            if ($depth === 1) {
443 2
                $argument = '[...]';
444 2
            } else {
445 13
                $sample = array();
446 13
                foreach ($argument as $key => $value) {
447 12
                    $key = is_int($key) ? $key : "'$key'";
448 12
                    $value = self::formatArgument($value, $depth + 1);
449 12
                    $sample[] = "$key => $value";
450 13
                }
451
452 13
                $argument = "[".implode(", ", $sample)."]";
453
            }
454
455 13
            return ((strlen($argument) > 1000) ? substr($argument, 0, 1000).'...]' : $argument);
456
        }
457
458 18
        if (is_bool($argument)) {
459 1
            return $argument ? 'true' : 'false';
460
        }
461
462 17
        if (is_resource($argument)) {
463 2
            return 'resource(...)';
464
        }
465
466 15
        if (is_null($argument)) {
467 1
            return 'NULL';
468
        }
469
470 14
        return "'".(string) $argument."'";
471
    }
472
473
    /**
474
     * Utility function to format objects to printable arrays.
475
     *
476
     * @param array $objects
477
     *
478
     * @return string
479
     */
480 54
    public static function formatObjects(array $objects = null)
481
    {
482 54
        static $formatting;
483
484 54
        if ($formatting) {
485 1
            return '[Recursion]';
486
        }
487
488 54
        if (is_null($objects)) {
489
            return '';
490
        }
491
492 54
        $objects = array_filter($objects, 'is_object');
493 54
        if (empty($objects)) {
494 47
            return '';
495
        }
496
497 7
        $formatting = true;
498 7
        $parts = array();
499
500 7
        foreach ($objects as $object) {
501 7
            $parts[get_class($object)] = self::objectToArray($object);
502 7
        }
503
504 7
        $formatting = false;
505
506 7
        return 'Objects: ( ' . var_export($parts, true) . ')';
507
    }
508
509
    /**
510
     * Utility function to turn public properties and public get* and is* method values into an array.
511
     *
512
     * @param     $object
513
     * @param int $nesting
514
     *
515
     * @return array
516
     */
517 7
    private static function objectToArray($object, $nesting = 3)
518
    {
519 7
        if ($nesting == 0) {
520
            return array('...');
521
        }
522
523
        return array(
524 7
            'class' => get_class($object),
525 7
            'properties' => self::extractInstancePublicProperties($object, $nesting),
526 7
            'getters' => self::extractGetters($object, $nesting)
527 7
        );
528
    }
529
530
    /**
531
     * Returns all public instance properties.
532
     *
533
     * @param $object
534
     * @param $nesting
535
     *
536
     * @return array
537
     */
538 7
    private static function extractInstancePublicProperties($object, $nesting)
539
    {
540 7
        $reflection = new \ReflectionClass(get_class($object));
541 7
        $properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC);
542 7
        $cleanedProperties = array();
543
544 7
        foreach ($properties as $publicProperty) {
545 1
            if (!$publicProperty->isStatic()) {
546
                $name = $publicProperty->getName();
547
                $cleanedProperties[$name] = self::cleanupNesting($object->$name, $nesting);
548
            }
549 7
        }
550
551 7
        return $cleanedProperties;
552
    }
553
554
    /**
555
     * Returns all object getters.
556
     *
557
     * @param $object
558
     * @param $nesting
559
     *
560
     * @return array
561
     */
562 7
    private static function extractGetters($object, $nesting)
563
    {
564 7
        $reflection = new \ReflectionClass(get_class($object));
565 7
        $publicMethods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
566 7
        $getters = array();
567
568 7
        foreach ($publicMethods as $publicMethod) {
569 5
            $name = $publicMethod->getName();
570 5
            $irrelevantName = (substr($name, 0, 3) !== 'get' && substr($name, 0, 2) !== 'is');
571 5
            $isStatic = $publicMethod->isStatic();
572 5
            $numberOfParameters = $publicMethod->getNumberOfParameters();
573
574 5
            if ($irrelevantName || $numberOfParameters != 0 || $isStatic) {
575 5
                continue;
576
            }
577
578
            try {
579 2
                $getters[$name] = self::cleanupNesting($object->$name(), $nesting);
580 2
            } catch (\Exception $e) {
581 1
                $getters[$name] = '!! ' . get_class($e) . ': ' . $e->getMessage() . ' !!';
582
            }
583 7
        }
584
585 7
        return $getters;
586
    }
587
588 1
    private static function cleanupNesting($argument, $nesting)
589
    {
590 1
        if (is_object($argument)) {
591
            $object = self::objectToArray($argument, $nesting - 1);
592
            $object['class'] = get_class($argument);
593
594
            return $object;
595
        }
596
597 1
        if (is_array($argument)) {
598 1
            return self::cleanupArray($argument, $nesting - 1);
599
        }
600
601 1
        return $argument;
602
    }
603
604 1
    private static function cleanupArray($argument, $nesting = 3)
605
    {
606 1
        if ($nesting == 0) {
607 1
            return '...';
608
        }
609
610 1
        foreach ($argument as $key => $value) {
611 1
            if (is_array($value)) {
612 1
                $argument[$key] = self::cleanupArray($value, $nesting - 1);
613 1
            } elseif (is_object($value)) {
614
                $argument[$key] = self::objectToArray($value, $nesting - 1);
615
            }
616 1
        }
617
618 1
        return $argument;
619
    }
620
621
    /**
622
     * Utility function to parse shouldReceive() arguments and generate
623
     * expectations from such as needed.
624
     *
625
     * @param Mockery\MockInterface $mock
626
     * @param array $args
627
     * @param callable $add
628
     * @return \Mockery\CompositeExpectation
629
     */
630 306
    public static function parseShouldReturnArgs(\Mockery\MockInterface $mock, $args, $add)
631
    {
632 306
        $composite = new \Mockery\CompositeExpectation();
633
634 306
        foreach ($args as $arg) {
635 306
            if (is_array($arg)) {
636 16
                foreach ($arg as $k => $v) {
637 16
                    $expectation = self::buildDemeterChain($mock, $k, $add)->andReturn($v);
638 16
                    $composite->add($expectation);
639 16
                }
640 306
            } elseif (is_string($arg)) {
641 294
                $expectation = self::buildDemeterChain($mock, $arg, $add);
642 288
                $composite->add($expectation);
643 288
            }
644 300
        }
645
646 300
        return $composite;
647
    }
648
649
    /**
650
     * Sets up expectations on the members of the CompositeExpectation and
651
     * builds up any demeter chain that was passed to shouldReceive.
652
     *
653
     * @param \Mockery\MockInterface $mock
654
     * @param string $arg
655
     * @param callable $add
656
     * @throws Mockery\Exception
657
     * @return \Mockery\ExpectationDirector
658
     */
659 306
    protected static function buildDemeterChain(\Mockery\MockInterface $mock, $arg, $add)
660
    {
661
        /** @var Mockery\Container $container */
662 306
        $container = $mock->mockery_getContainer();
663 306
        $methodNames = explode('->', $arg);
664 306
        reset($methodNames);
665
666 306
        if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed()
667 306
            && !$mock->mockery_isAnonymous()
668 306
            && !in_array(current($methodNames), $mock->mockery_getMockableMethods())
669 306
        ) {
670 4
            throw new \Mockery\Exception(
671
                'Mockery\'s configuration currently forbids mocking the method '
672 4
                . current($methodNames) . ' as it does not exist on the class or object '
673 4
                . 'being mocked'
674 4
            );
675
        }
676
677
        /** @var ExpectationInterface|null $expectations */
678 302
        $expectations = null;
679
680
        /** @var Callable $nextExp */
681
        $nextExp = function ($method) use ($add) {
682 302
            return $add($method);
683 302
        };
684
685 302
        while (true) {
686 302
            $method = array_shift($methodNames);
687 302
            $expectations = $mock->mockery_getExpectationsFor($method);
688
689 302
            if (is_null($expectations) || self::noMoreElementsInChain($methodNames)) {
690 302
                $expectations = $nextExp($method);
691 300
                if (self::noMoreElementsInChain($methodNames)) {
692 300
                    break;
693
                }
694
695 11
                $mock = self::getNewDemeterMock($container, $method, $expectations);
696 11
            } else {
697 5
                $demeterMockKey = $container->getKeyOfDemeterMockFor($method);
698 5
                if ($demeterMockKey) {
699 5
                    $mock = self::getExistingDemeterMock($container, $demeterMockKey);
700 5
                }
701
            }
702
703 11
            $nextExp = function ($n) use ($mock) {
704 11
                return $mock->shouldReceive($n);
705 11
            };
706 11
        }
707
708 300
        return $expectations;
709
    }
710
711
    /**
712
     * @param \Mockery\Container $container
713
     * @param string $method
714
     * @param Mockery\ExpectationInterface $exp
715
     *
716
     * @return \Mockery\Mock
717
     */
718 11
    private static function getNewDemeterMock(Mockery\Container $container,
719
        $method,
720
        Mockery\ExpectationInterface $exp
721
    ) {
722 11
        $mock = $container->mock('demeter_' . $method);
723 11
        $exp->andReturn($mock);
724
725 11
        return $mock;
726
    }
727
728
    /**
729
     * @param \Mockery\Container $container
730
     * @param string $demeterMockKey
731
     *
732
     * @return mixed
733
     */
734 5
    private static function getExistingDemeterMock(Mockery\Container $container, $demeterMockKey)
735
    {
736 5
        $mocks = $container->getMocks();
737 5
        $mock = $mocks[$demeterMockKey];
738
739 5
        return $mock;
740
    }
741
742
    /**
743
     * @param array $methodNames
744
     *
745
     * @return bool
746
     */
747 300
    private static function noMoreElementsInChain(array $methodNames)
748
    {
749 300
        return empty($methodNames);
750
    }
751
752
    /**
753
     * Register a file to be deleted on tearDown.
754
     *
755
     * @param string $fileName
756
     */
757 17
    public static function registerFileForCleanUp($fileName)
758
    {
759 17
        self::$_filesToCleanUp[] = $fileName;
760 17
    }
761
}
762