Completed
Push — develop ( 978c73...c86111 )
by ANTHONIUS
13s queued 11s
created

Cache::getProcessor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
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 SebastianBergmann\CodeCoverage\Filter;
17
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
18
19
class Cache implements \Serializable
20
{
21
    const CACHE_KEY = 'subject';
22
23
    /**
24
     * @var string|null
25
     */
26
    private $namespace;
27
28
    /**
29
     * @var TestCase
30
     */
31
    private $testCase;
32
33
    /**
34
     * @var FilesystemAdapter|null
35
     */
36
    private $adapter;
37
38
    /**
39
     * @var array
40
     */
41
    private $data = [];
42
43
    /**
44
     * @var array
45
     */
46
    private $filter = [];
47
48
    /**
49
     * @var Processor
50
     */
51
    private $processor;
52
53
    /**
54
     * @var array
55
     */
56
    private $codeCoverageOptions = [];
57
58
    /**
59
     * @var \Exception[]
60
     */
61
    private $exceptions = [];
62
63
    /**
64
     * @var bool
65
     */
66
    private $hasStarted = false;
67
68 20
    public function __construct($namespace)
69
    {
70 20
        $dir             = sys_get_temp_dir().'/doyo/behat-coverage-extension';
71 20
        $adapter         = new FilesystemAdapter($namespace, 0, $dir);
72 20
        $this->adapter   = $adapter;
73 20
        $this->namespace = $namespace;
74
75 20
        $this->readCache();
76
    }
77
78 13
    public function reset()
79
    {
80 13
        $this->testCase     = null;
81 13
        $this->data         = [];
82 13
        $this->exceptions   = [];
83 13
        $this->processor = null;
84
85 13
        $this->save();
86
    }
87
88 20
    public function serialize()
89
    {
90
        $data = [
91 20
            $this->testCase,
92 20
            $this->data,
93 20
            $this->codeCoverageOptions,
94 20
            $this->filter,
95 20
            $this->exceptions,
96
        ];
97
98 20
        return serialize($data);
99
    }
100
101 18
    public function unserialize($serialized)
102
    {
103
        list(
104 18
            $this->testCase,
105 18
            $this->data,
106 18
            $this->codeCoverageOptions,
107 18
            $this->filter,
108 18
            $this->exceptions
109 18
        ) = unserialize($serialized);
110
    }
111
112 20
    public function readCache()
113
    {
114 20
        $adapter = $this->adapter;
115 20
        $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

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