Completed
Push — master ( 7ee214...32fd8d )
by Alberto
19s
created

AbstractMockingStrategy::call()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 6
ccs 3
cts 3
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Moka\Strategy;
5
6
use Moka\Exception\InvalidArgumentException;
7
use Moka\Exception\MissingDependencyException;
8
use Moka\Exception\MockNotCreatedException;
9
use Moka\Exception\NotImplementedException;
10
use Moka\Factory\StubFactory;
11
use Moka\Stub\MethodStub;
12
use Moka\Stub\PropertyStub;
13
use Moka\Stub\StubInterface;
14
15
/**
16
 * Class AbstractMockingStrategy
17
 * @package Moka\Strategy
18
 */
19
abstract class AbstractMockingStrategy implements MockingStrategyInterface
20
{
21
    /**
22
     * @var string
23
     */
24
    private $mockType;
25
26
    /**
27
     * @param string $dependencyClassName
28
     * @param string $dependencyPackageName
29
     *
30
     * @throws MissingDependencyException
31
     */
32 10
    final protected static function checkDependencies(string $dependencyClassName, string $dependencyPackageName)
33
    {
34 10
        if (!class_exists($dependencyClassName)) {
35 1
            throw new MissingDependencyException(
36 1
                sprintf(
37 1
                    'Class "%s" does not exist, please install package "%s"',
38 1
                    $dependencyClassName,
39 1
                    $dependencyPackageName
40
                )
41
            );
42
        }
43
    }
44
45
    /**
46
     * @param string $fqcn
47
     * @return object
48
     *
49
     * @throws MockNotCreatedException
50
     */
51 102
    public function build(string $fqcn)
52
    {
53
        try {
54 102
            return $this->doBuild($fqcn);
55 11
        } catch (\Throwable $exception) {
56 11
            throw new MockNotCreatedException(
57 11
                sprintf(
58 11
                    'Cannot create mock object for FQCN "%s": %s',
59 11
                    $fqcn,
60 11
                    $exception->getMessage()
61
                )
62
            );
63
        }
64
    }
65
66
    /**
67
     * @param object $mock
68
     * @param StubInterface[] $stubs
69
     * @return void
70
     *
71
     * @throws InvalidArgumentException
72
     * @throws NotImplementedException
73
     */
74 94
    public function decorate($mock, array $stubs)
75
    {
76 94
        $this->checkMockType($mock);
77
78 94
        $stubs = StubFactory::fromArray($stubs);
79
80 94
        foreach ($stubs as $stub) {
81 94
            if ($stub instanceof PropertyStub) {
82 4
                $this->doDecorateWithProperty($mock, $stub);
83
            }
84
85 94
            if ($stub instanceof MethodStub) {
86 94
                $this->doDecorateWithMethod($mock, $stub);
87
            }
88
        }
89
    }
90
91
    /**
92
     * @param object $mock
93
     * @return object
94
     *
95
     * @throws NotImplementedException
96
     * @throws InvalidArgumentException
97
     */
98 62
    public function get($mock)
99
    {
100 62
        $this->checkMockType($mock);
101
102 58
        return $this->doGet($mock);
103
    }
104
105
    /**
106
     * @param object $mock
107
     * @param string $methodName
108
     * @return mixed
109
     *
110
     * @throws NotImplementedException
111
     */
112 3
    public function call($mock, string $methodName)
113
    {
114 3
        $this->checkMockType($mock);
115
116 3
        return $this->doCall($mock, $methodName);
117
    }
118
119
    /**
120
     * @return string
121
     *
122
     * @throws NotImplementedException
123
     */
124 23
    public function getMockType(): string
125
    {
126 23
        $this->verifyMockType();
127
128 22
        return $this->mockType;
129
    }
130
131
    /**
132
     * @param string $fqcn
133
     */
134 10
    final protected function setMockType(string $fqcn)
135
    {
136 10
        $this->mockType = $fqcn;
137
    }
138
139
    /**
140
     * @param object $mock
141
     *
142
     * @throws NotImplementedException
143
     * @throws InvalidArgumentException
144
     */
145 103
    final protected function checkMockType($mock)
146
    {
147 103
        $this->verifyMockType();
148
149 103
        if (!is_a($mock, $this->mockType)) {
150 8
            throw new InvalidArgumentException(
151 8
                sprintf(
152 8
                    'Mock object must be an instance of "%s", "%s" given',
153 8
                    $this->mockType,
154 8
                    gettype($mock)
155
                )
156
            );
157
        }
158
    }
159
160
    /**
161
     * @return void
162
     *
163
     * @throws NotImplementedException
164
     */
165 104
    private function verifyMockType()
166
    {
167 104
        if (!$this->mockType) {
168 1
            throw new NotImplementedException('Mock type was not defined');
169
        }
170
    }
171
172
    /**
173
     * @param string $fqcn
174
     * @return object
175
     */
176
    abstract protected function doBuild(string $fqcn);
177
178
    /**
179
     * @param object $mock
180
     * @param PropertyStub $stub
181
     * @return void
182
     */
183 4
    protected function doDecorateWithProperty($mock, PropertyStub $stub)
184
    {
185 4
        $mock->{$stub->getName()} = $stub->getValue();
186
    }
187
188
    /**
189
     * @param object $mock
190
     * @param MethodStub $stub
191
     * @return void
192
     */
193
    abstract protected function doDecorateWithMethod($mock, MethodStub $stub);
194
195
    /**
196
     * @param object $mock
197
     * @return object
198
     */
199
    abstract protected function doGet($mock);
200
201
    /**
202
     * @param object $mock
203
     * @param string $methodName
204
     * @return mixed
205
     *
206
     * @throws \Error
207
     */
208 1
    protected function doCall($mock, string $methodName)
209
    {
210 1
        throw new \Error(
211 1
            sprintf(
1 ignored issue
show
Unused Code introduced by
The call to Error::__construct() has too many arguments starting with sprintf('Undefined prope...ss($this), $methodName).

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...
212 1
                'Undefined property: %s::$%s',
213 1
                get_class($this),
214 1
                $methodName
215
            )
216
        );
217
    }
218
}
219