Passed
Pull Request — develop (#5)
by ANTHONIUS
04:10
created

CachedCoverage::startCoverage()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3.6511

Importance

Changes 0
Metric Value
cc 3
eloc 12
nc 4
nop 1
dl 0
loc 18
ccs 7
cts 12
cp 0.5833
crap 3.6511
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
namespace Doyo\Behat\Coverage\Bridge\CodeCoverage;
4
5
use Doyo\Behat\Coverage\Event\CoverageEvent;
6
use SebastianBergmann\CodeCoverage\CodeCoverage;
7
use SebastianBergmann\CodeCoverage\Filter;
8
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
9
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
10
11
class CachedCoverage implements \Serializable, EventSubscriberInterface
12
{
13
    const CACHE_KEY = 'subject';
14
15
    /**
16
     * @var null|string
17
     */
18
    private $namespace;
19
20
    /**
21
     * @var null|string
22
     */
23
    private $coverageId;
24
25
    /**
26
     * @var null|FilesystemAdapter
27
     */
28
    private $adapter;
29
30
    /**
31
     * @var array
32
     */
33
    private $coverage = [];
34
35
    /**
36
     * @var array
37
     */
38
    private $filter = [];
39
40
    /**
41
     * @var CodeCoverage
42
     */
43
    private $codeCoverage;
44
45
    /**
46
     * @var \Exception[]
47
     */
48
    private $exceptions = [];
49
50 16
    public function __construct($namespace)
51
    {
52 16
        $dir = sys_get_temp_dir().'/doyo/behat-coverage-extension';
53 16
        $adapter = new FilesystemAdapter($namespace,0, $dir);
54 16
        $this->adapter = $adapter;
55 16
        $this->namespace = $namespace;
56
57 16
        $this->readCache();
58
    }
59
60 15
    public function initialize()
61
    {
62 15
        $this->coverageId = null;
63 15
        $this->coverage = [];
64 15
        $this->exceptions = [];
65
66 15
        $this->save();
67
    }
68
69 16
    public function serialize()
70
    {
71
        $data = [
72 16
            $this->coverageId,
73 16
            $this->coverage
74
        ];
75 16
        return serialize($data);
76
    }
77
78 14
    public function unserialize($serialized)
79
    {
80 14
        list($this->coverageId, $this->coverage) = unserialize($serialized);
81
    }
82
83
    /**
84
     * @return string|null
85
     */
86 1
    public function getNamespace()
87
    {
88 1
        return $this->namespace;
89
    }
90
91
    /**
92
     * @return string|null
93
     */
94 14
    public function getCoverageId()
95
    {
96 14
        return $this->coverageId;
97
    }
98
99
    /**
100
     * @param string|null $coverageId
101
     * @return CachedCoverage
102
     */
103 3
    public function setCoverageId(string $coverageId): CachedCoverage
104
    {
105 3
        $this->coverageId = $coverageId;
106 3
        return $this;
107
    }
108
109
    /**
110
     * @return FilesystemAdapter|null
111
     */
112 1
    public function getAdapter(): FilesystemAdapter
113
    {
114 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...
115
    }
116
117
    /**
118
     * @param FilesystemAdapter|null $adapter
119
     * @return CachedCoverage
120
     */
121 1
    public function setAdapter(FilesystemAdapter $adapter): CachedCoverage
122
    {
123 1
        $this->adapter = $adapter;
124 1
        return $this;
125
    }
126
127
    /**
128
     * @return array
129
     */
130 14
    public function getCoverage(): array
131
    {
132 14
        return $this->coverage;
133
    }
134
135
    /**
136
     * @param array $coverage
137
     * @return CachedCoverage
138
     */
139 4
    public function setCoverage(array $coverage): CachedCoverage
140
    {
141 4
        $this->coverage = $coverage;
142 4
        return $this;
143
    }
144
145 1
    public function getFilter(): array
146
    {
147 1
        return $this->filter;
148
    }
149
150
    /**
151
     * @param  Filter|array $filter
152
     *
153
     * @return $this
154
     */
155 4
    public function setFilter($filter)
156
    {
157 4
        if($filter instanceof Filter){
158 2
            $whitelistedFiles = $filter->getWhitelistedFiles();
159 2
            $filter = [];
160 2
            $filter['addFilesToWhitelist'] = $whitelistedFiles;
161
        }
162
163 4
        $this->filter = $filter;
164
165 4
        return $this;
166
    }
167
168 16
    public function save()
169
    {
170 16
        $adapter = $this->adapter;
171 16
        $item = $adapter->getItem(static::CACHE_KEY);
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

171
        /** @scrutinizer ignore-call */ 
172
        $item = $adapter->getItem(static::CACHE_KEY);

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...
172 16
        $item->set($this);
173 16
        $adapter->save($item);
174
    }
175
176 16
    public function readCache()
177
    {
178 16
        $adapter = $this->adapter;
179
        $cached = $adapter->get(static::CACHE_KEY, function(){
180 2
            return false;
181 16
        });
182
183 16
        if($cached instanceof CachedCoverage){
184 14
            $this->coverageId = $cached->getCoverageId();
185 14
            $this->coverage = $cached->getCoverage();
186
        }
187
    }
188
189 3
    public static function getSubscribedEvents()
190
    {
191
        return [
192 3
            CoverageEvent::REFRESH => 'onCoverageRefresh',
193 2
            CoverageEvent::START => 'onCoverageStarted',
194 2
            CoverageEvent::STOP => ['onCoverageStopped', 10],
195
        ];
196
    }
197
198
    /**
199
     * @return Filter
200
     */
201 2
    public function createFilter()
202
    {
203 2
        $config = $this->filter;
204 2
        $filter = new Filter();
205 2
        foreach ($config as $method => $value){
206 1
            call_user_func_array([$filter, $method], [$value]);
207
        }
208 2
        return $filter;
209
    }
210
211 2
    public function startCoverage($driver = null)
212
    {
213 1
        if(is_null($this->coverageId)){
214
            return;
215
        }
216 1
        $filter = $this->createFilter();
217
        try{
218 1
            $coverage = new CodeCoverage($driver, $filter);
219 1
            $coverage->start($this->getCoverageId());
220
221 2
            $this->codeCoverage = $coverage;
222
        }catch (\Exception $e){
223
            $this->exceptions[] = sprintf(
224
                "Error in starting code coverage:\n%s",
225
                $e->getMessage()
226
            );
227
        }
228 2
        register_shutdown_function([$this,'shutdown']);
229
    }
230
231 2
    public function onCoverageRefresh()
232
    {
233 2
        $this->initialize();
234
    }
235
236 2
    public function onCoverageStarted(CoverageEvent $event)
237
    {
238 2
        $this->coverageId = $event->getCoverageId();
239 2
        $this->save();
240
    }
241
242 2
    public function onCoverageStopped(CoverageEvent $event)
243
    {
244 2
        $this->readCache();
245 2
        $event->updateCoverage($this->coverage);
246
    }
247
248 2
    public function shutdown()
249
    {
250 2
        $codeCoverage = $this->codeCoverage;
251
252 2
        if(is_null($codeCoverage)){
253
            return;
254
        }
255
256 2
        $data = $codeCoverage->stop();
257 1
        $this->coverage = $data;
258 1
        $this->save();
259 1
        $this->codeCoverage = null;
260
    }
261
}
262