Completed
Pull Request — master (#6)
by Alberto
04:09
created

ProphecyMockingStrategy::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
crap 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Moka\Strategy;
5
6
use Moka\Exception\InvalidArgumentException;
7
use Moka\Exception\MockNotCreatedException;
8
use Moka\Strategy\Prophecy\LowPriorityToken;
9
use Moka\Strategy\Prophecy\NoPriorityToken;
10
use Moka\Stub\Stub;
11
use Moka\Stub\StubSet;
12
use Prophecy\Exception\Prophecy\ObjectProphecyException;
13
use Prophecy\Prophecy\ObjectProphecy;
14
use Prophecy\Prophet;
15
16
/**
17
 * Class ProphecyMockingStrategy
18
 * @package Moka\Strategy
19
 */
20
class ProphecyMockingStrategy extends AbstractMockingStrategy
21
{
22
    /**
23
     * @var Prophet
24
     */
25
    private $prophet;
26
27
    /**
28
     * PHPUnitMockingStrategy constructor.
29
     */
30 1
    public function __construct()
31
    {
32 1
        $this->prophet = new Prophet();
33 1
        $this->setMockType(ObjectProphecy::class);
34
    }
35
36
    /**
37
     * @param string $fqcn
38
     * @return ObjectProphecy
39
     *
40
     * @throws MockNotCreatedException
41
     */
42 3
    public function build(string $fqcn)
43
    {
44
        try {
45 3
            $mock = $this->prophet->prophesize($fqcn);
46
47 3
            $methodNames = $this->filterMethods($fqcn);
48 3
            foreach ($methodNames as $methodName) {
49 3
                $mock->$methodName(new NoPriorityToken())->willReturn(null);
50
            }
51
        } catch (\Exception $exception) {
52
            // This should never be reached.
53
            throw new MockNotCreatedException(
54
                sprintf(
55
                    'Unable to create mock object for FQCN %s',
56
                    $fqcn
57
                )
58
            );
59
        }
60
61 3
        return $mock;
62
    }
63
64
    /**
65
     * @param ObjectProphecy $mock
66
     * @param StubSet $stubs
67
     * @return void
68
     *
69
     * @throws InvalidArgumentException
70
     */
71 2
    public function decorate($mock, StubSet $stubs)
72
    {
73 2
        $this->checkMockType($mock);
74
75
        /** @var Stub $stub */
76 1
        foreach ($stubs as $stub) {
77 1
            $methodName = $stub->getMethodName();
78 1
            $methodValue = $stub->getMethodValue();
79
80 1
            $methodValue instanceof \Exception
81 1
                ? $mock->$methodName(new LowPriorityToken())->willThrow($methodValue)
82 1
                : $mock->$methodName(new LowPriorityToken())->willReturn($methodValue);
83
        }
84
    }
85
86
    /**
87
     * @param ObjectProphecy $mock
88
     * @return object
89
     *
90
     * @throws InvalidArgumentException
91
     * @throws MockNotCreatedException
92
     */
93 4
    public function get($mock)
94
    {
95 4
        $this->checkMockType($mock);
96
97
        try {
98 3
            return $mock->reveal();
99 1
        } catch (ObjectProphecyException $exception) {
100 1
            throw new MockNotCreatedException('Unable to create mock object');
101
        }
102
    }
103
104
    /**
105
     * @param string $fqcn
106
     * @return string[]
107
     */
108 3
    protected function filterMethods(string $fqcn): array
109
    {
110
        // The result is empty for nonexistent FQCNs (or empty ones).
111 3
        $methodNames = get_class_methods($fqcn) ?: [];
112
113
        // Filter magic and final methods.
114 3
        return array_filter($methodNames, function ($methodName) use ($fqcn) {
115 3
            if (preg_match('/^__/', $methodName)) {
116 3
                return false;
117
            }
118
119 3
            $reflectionMethod = new \ReflectionMethod($fqcn, $methodName);
120 3
            if ($reflectionMethod->isFinal()) {
121 3
                return false;
122
            }
123
124 3
            return true;
125 3
        });
126
    }
127
}
128