Passed
Pull Request — develop (#8)
by ANTHONIUS
04:35
created

Cache::createCodeCoverageFilter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
ccs 6
cts 6
cp 1
crap 2
1
<?php
2
3
/*
4
 * This file is part of the doyo/behat-coverage-extension project.
5
 *
6
 * (c) Anthonius Munthi <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Doyo\Behat\Coverage\Bridge\CodeCoverage;
15
16
use Doyo\Behat\Coverage\Bridge\Exception\CacheException;
17
use SebastianBergmann\CodeCoverage\Filter;
18
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
19
20
class Cache implements \Serializable
21
{
22
    const CACHE_KEY = 'subject';
23
24
    /**
25
     * @var string|null
26
     */
27
    private $namespace;
28
29
    /**
30
     * @var TestCase
31
     */
32
    private $testCase;
33
34
    /**
35
     * @var FilesystemAdapter|null
36
     */
37
    private $adapter;
38
39
    /**
40
     * @var array
41
     */
42
    private $data = [];
43
44
    /**
45
     * @var array
46
     */
47
    private $filter = [];
48
49
    /**
50
     * @var Processor
51
     */
52
    private $processor;
53
54
    /**
55
     * @var array
56
     */
57
    private $codeCoverageOptions = [];
58
59
    /**
60
     * @var \Exception[]
61
     */
62
    private $exceptions = [];
63
64
    /**
65
     * @var bool
66
     */
67
    private $hasStarted = false;
68
69 25
    public function __construct($namespace)
70
    {
71 25
        $dir             = sys_get_temp_dir().'/doyo/behat-coverage-extension';
72 25
        $adapter         = new FilesystemAdapter($namespace, 0, $dir);
73 25
        $this->adapter   = $adapter;
74 25
        $this->namespace = $namespace;
75
76 25
        $this->readCache();
77 1
    }
78
79 16
    public function reset()
80
    {
81 16
        $this->testCase     = null;
82 16
        $this->data         = [];
83 16
        $this->exceptions   = [];
84 16
        $this->processor = null;
85
86 16
        $this->save();
87
    }
88
89 26
    public function serialize()
90
    {
91
        $data = [
92 26
            $this->testCase,
93 26
            $this->data,
94 26
            $this->codeCoverageOptions,
95 26
            $this->filter,
96 26
            $this->exceptions,
97
        ];
98
99 26
        return serialize($data);
100
    }
101
102 23
    public function unserialize($serialized)
103
    {
104
        list(
105 23
            $this->testCase,
106 23
            $this->data,
107 23
            $this->codeCoverageOptions,
108 23
            $this->filter,
109 23
            $this->exceptions
110 23
        ) = unserialize($serialized);
111
    }
112
113 26
    public function readCache()
114
    {
115 26
        $adapter = $this->adapter;
116 26
        $cached  = $adapter->getItem(static::CACHE_KEY)->get();
0 ignored issues
show
Bug introduced by
The method getItem() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

116
        $cached  = $adapter->/** @scrutinizer ignore-call */ getItem(static::CACHE_KEY)->get();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
117
118 26
        if ($cached instanceof self) {
119 23
            $this->testCase            = $cached->getTestCase();
120 23
            $this->data                = $cached->getData()?:[];
121 23
            $this->exceptions          = $cached->getExceptions();
122 23
            $this->filter              = $cached->getFilter();
123 23
            $this->codeCoverageOptions = $cached->getCodeCoverageOptions();
124
        }
125 1
    }
126
127
    /**
128
     * @return string|null
129
     */
130 1
    public function getNamespace()
131
    {
132 1
        return $this->namespace;
133
    }
134
135
    /**
136
     * @return TestCase
137
     */
138 23
    public function getTestCase()
139
    {
140 23
        return $this->testCase;
141
    }
142
143
    /**
144
     * @param TestCase $testCase
145
     *
146
     * @return Cache
147
     */
148 18
    public function setTestCase(TestCase $testCase = null)
149
    {
150 18
        $this->testCase = $testCase;
151
152 18
        return $this;
153
    }
154
155
    /**
156
     * @return FilesystemAdapter|null
157
     */
158 1
    public function getAdapter(): FilesystemAdapter
159
    {
160 1
        return $this->adapter;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->adapter could return the type null which is incompatible with the type-hinted return Symfony\Component\Cache\Adapter\FilesystemAdapter. Consider adding an additional type-check to rule them out.
Loading history...
161
    }
162
163
    /**
164
     * @param FilesystemAdapter|null $adapter
165
     *
166
     * @return Cache
167
     */
168 1
    public function setAdapter(FilesystemAdapter $adapter): self
169
    {
170 1
        $this->adapter = $adapter;
171
172 1
        return $this;
173
    }
174
175
    /**
176
     * @return array
177
     */
178 23
    public function getData()
179
    {
180 23
        return $this->data;
181
    }
182
183
    /**
184
     * @param array $data
185
     *
186
     * @return Cache
187
     */
188 2
    public function setData(array $data)
189
    {
190 2
        $this->data = $data;
191
    }
192
193
    /**
194
     * @return array
195
     */
196 23
    public function getCodeCoverageOptions(): array
197
    {
198 23
        return $this->codeCoverageOptions;
199
    }
200
201
    /**
202
     * @param array $codeCoverageOptions
203
     *
204
     * @return Cache
205
     */
206 13
    public function setCodeCoverageOptions(array $codeCoverageOptions): self
207
    {
208 13
        $this->codeCoverageOptions = $codeCoverageOptions;
209
210 13
        return $this;
211
    }
212
213
    /**
214
     * @param Processor $processor
215
     *
216
     * @return Cache
217
     */
218 14
    public function setProcessor(Processor $processor = null)
219
    {
220 14
        $this->processor = $processor;
221
222 14
        return $this;
223
    }
224
225 1
    public function getProcessor()
226
    {
227 1
        return $this->processor;
228
    }
229
230 23
    public function getFilter(): array
231
    {
232 23
        return $this->filter;
233
    }
234
235
    /**
236
     * @param Filter|array $filter
237
     *
238
     * @return $this
239
     */
240 13
    public function setFilter($filter)
241
    {
242 13
        if ($filter instanceof Filter) {
243 9
            $whitelistedFiles              = $filter->getWhitelistedFiles();
244 9
            $filter                        = [];
245 9
            $filter['addFilesToWhitelist'] = $whitelistedFiles;
246
        }
247
248 13
        $this->filter = $filter;
249
250 13
        return $this;
251
    }
252
253 6
    public function hasExceptions()
254
    {
255 6
        return \count($this->exceptions) > 0;
256
    }
257
258 23
    public function getExceptions()
259
    {
260 23
        return $this->exceptions;
261
    }
262
263 26
    public function save()
264
    {
265 26
        $adapter = $this->adapter;
266 26
        $item    = $adapter->getItem(static::CACHE_KEY);
267
268 26
        $item->set($this);
269 26
        $adapter->save($item);
270 1
    }
271
272
    /**
273
     * @return Filter
274
     */
275 1
    private function createCodeCoverageFilter()
276
    {
277 1
        $config = $this->filter;
278 1
        $filter = new Filter();
279 1
        foreach ($config as $method => $value) {
280 1
            \call_user_func_array([$filter, $method], [$value]);
281
        }
282
283 1
        return $filter;
284
    }
285
286 6
    public function startCoverage($driver = null)
287
    {
288 5
        if (null === $this->testCase) {
289 1
            return;
290
        }
291
        try {
292 4
            $processor = $this->processor;
293 4
            if(is_null($processor)){
294 1
                $processor = $this->createCodeCoverage($driver);
295
            }
296 4
            $processor->start($this->getTestCase());
297 6
            register_shutdown_function([$this, 'shutdown']);
298 6
            $this->hasStarted = true;
299 2
        } catch (\Exception $e) {
300 2
            $message = sprintf(
301 2
                "Can not start code coverage in namespace: %s :\n%s",
302 2
                $this->namespace,
303 2
                $e->getMessage()
304
            );
305 2
            $this->exceptions[] = $message;
306
        }
307 2
    }
308
309 7
    public function shutdown()
310
    {
311 7
        $processor = $this->processor;
312 7
        if ($this->hasStarted) {
313
            try {
314 6
                $data               = $processor->stop();
315 1
                $this->data         = $data;
316 1
            } catch (\Exception $e) {
317 1
                $this->exceptions[] = new CacheException($e->getMessage());
318
            }
319
        }
320 3
        $this->processor    = null;
321 3
        $this->hasStarted   = false;
322 3
        $this->save();
323
    }
324
325
    /**
326
     * @param mixed|null $driver
327
     *
328
     * @return Processor
329
     */
330 1
    private function createCodeCoverage($driver = null)
331
    {
332 1
        $coverage = $this->processor;
333 1
        $filter   = $this->createCodeCoverageFilter();
334 1
        $options  = $this->codeCoverageOptions;
335
336 1
        if (null === $coverage) {
337 1
            $coverage        = new Processor($driver, $filter);
338 1
            $this->processor = $coverage;
339
        }
340
341 1
        foreach ($options as $method => $option) {
342 1
            $method = 'set'.ucfirst($method);
343 1
            \call_user_func_array([$coverage, $method], [$option]);
344
        }
345
346 1
        return $coverage;
347
    }
348
}
349