Completed
Pull Request — master (#6)
by Angelo
02:47
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: %s',
56
                    $fqcn,
57
                    $exception->getMessage()
58
                )
59
            );
60
        }
61
62 3
        return $mock;
63
    }
64
65
    /**
66
     * @param ObjectProphecy $mock
67
     * @param StubSet $stubs
68
     * @return void
69
     *
70
     * @throws InvalidArgumentException
71
     */
72 2
    public function decorate($mock, StubSet $stubs)
73
    {
74 2
        $this->checkMockType($mock);
75
76
        /** @var Stub $stub */
77 1
        foreach ($stubs as $stub) {
78 1
            $methodName = $stub->getMethodName();
79 1
            $methodValue = $stub->getMethodValue();
80
81 1
            $methodValue instanceof \Throwable
82 1
                ? $mock->$methodName(new LowPriorityToken())->willThrow($methodValue)
83 1
                : $mock->$methodName(new LowPriorityToken())->willReturn($methodValue);
84
        }
85
    }
86
87
    /**
88
     * @param ObjectProphecy $mock
89
     * @return object
90
     *
91
     * @throws InvalidArgumentException
92
     * @throws MockNotCreatedException
93
     */
94 4
    public function get($mock)
95
    {
96 4
        $this->checkMockType($mock);
97
98
        try {
99 3
            return $mock->reveal();
100 1
        } catch (ObjectProphecyException $exception) {
101 1
            throw new MockNotCreatedException(
102 1
                sprintf(
103 1
                    'Unable to create mock object: %s',
104 1
                    $exception->getMessage()
105
                )
106
            );
107
        }
108
    }
109
110
    /**
111
     * @param string $fqcn
112
     * @return string[]
113
     */
114 3
    protected function filterMethods(string $fqcn): array
115
    {
116
        // The result is empty for nonexistent FQCNs (or empty ones).
117 3
        $methodNames = get_class_methods($fqcn) ?: [];
118
119
        // Filter magic and final methods.
120 3
        return array_filter($methodNames, function ($methodName) use ($fqcn) {
121 3
            if (preg_match('/^__/', $methodName)) {
122 3
                return false;
123
            }
124
125 3
            $reflectionMethod = new \ReflectionMethod($fqcn, $methodName);
126 3
            if ($reflectionMethod->isFinal()) {
127 3
                return false;
128
            }
129
130 3
            return true;
131 3
        });
132
    }
133
}
134