Passed
Push — master ( a5bee2...63ddd2 )
by Pierre
32:12 queued 15s
created

Checker   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 266
Duplicated Lines 0 %

Test Coverage

Coverage 96.67%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 79
dl 0
loc 266
ccs 87
cts 90
cp 0.9667
rs 9.84
c 1
b 0
f 0
wmc 32

18 Methods

Rating   Name   Duplication   Size   Complexity  
A setResults() 0 12 1
A check() 0 14 3
A exists() 0 3 1
A parse() 0 16 4
A getClassesRatio() 0 8 2
A getStatementsRatio() 0 8 2
A getResults() 0 3 1
A getMethodsRatio() 0 5 2
A setContent() 0 6 2
A init() 0 8 1
A getMsgLine() 0 9 2
A getContent() 0 3 1
A run() 0 6 2
A getRatio() 0 3 1
A __construct() 0 4 1
A getElementsRatio() 0 5 2
A shutdown() 0 6 3
A isBlocking() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PierInfor\Undercover;
6
7
use PierInfor\Undercover\Interfaces\IChecker;
8
use PierInfor\Undercover\Args;
9
10
/**
11
 * Checker is a coverage cover format file checker
12
 *
13
 * @author Pierre Fromager <info@pier_infor.fr>
14
 * @version 1.0
15
 * @package PierInfor\Undercover
16
 */
17
class Checker implements IChecker
18
{
19
20
    protected $cloverArgs;
21
    protected $filename;
22
    protected $content;
23
    protected $error;
24
    protected $results;
25
    protected $thresholds;
26
27
    /**
28
     * constructor
29
     */
30 14
    public function __construct()
31
    {
32 14
        $this->cloverArgs = new Args();
33 14
        $this->init();
34
    }
35
36
    /**
37
     * runner
38
     *
39
     * @return Checker
40
     */
41 1
    public function run(): Checker
42
    {
43 1
        if (!empty($this->getContent())) {
44 1
            $this->parse()->check()->shutdown();
45
        }
46 1
        return $this;
47
    }
48
49
    /**
50
     * initializer
51
     *
52
     * @return Checker
53
     */
54 1
    protected function init(): Checker
55
    {
56 1
        $this->filename = $this->cloverArgs->getFilename();
57 1
        $this->setContent();
58 1
        $this->error = false;
59 1
        $this->thresholds = $this->cloverArgs->getThresholds();
60 1
        $this->results = [];
61 1
        return $this;
62
    }
63
64
    /**
65
     * parse xml clover file and set coverage results
66
     *
67
     * @return Checker
68
     */
69 1
    protected function parse(): Checker
70
    {
71 1
        $xml = new \SimpleXMLElement($this->getContent());
72 1
        $metrics = $xml->project->metrics;
73 1
        $classes = $xml->xpath(self::XPATH_SEARCH);
74 1
        $coveredClasses = 0;
75 1
        foreach ($classes as $class) {
76 1
            $methods = (int) $class->metrics[Args::_METHODS];
77 1
            $areMethodsCovered = ($methods > 0
78 1
                && $methods === (int) $class->metrics[self::COVERED_METHODS]);
79 1
            if ($areMethodsCovered) {
80 1
                $coveredClasses++;
81
            }
82
        }
83 1
        $this->setResults($coveredClasses, $metrics);
84 1
        return $this;
85
    }
86
87
    /**
88
     * returns result metrics coverage ratios as array
89
     *
90
     * @return string
91
     */
92 1
    protected function getResults(): array
93
    {
94 1
        return $this->results;
95
    }
96
97
    /**
98
     * returns coverage file content
99
     *
100
     * @return string
101
     */
102 1
    protected function getContent(): string
103
    {
104 1
        return $this->content;
105
    }
106
107
    /**
108
     * display msg and set error if under coverage
109
     *
110
     * @return Checker
111
     */
112 1
    protected function check(): Checker
113
    {
114 1
        echo self::TITLE;
115 1
        $errCount = 0;
116 1
        foreach ($this->results as $k => $v) {
117 1
            $valid = $v >= $this->thresholds[$k];
118 1
            if (!$valid) {
119
                ++$errCount;
120
            }
121 1
            echo PHP_EOL . $this->getMsgLine($k, $v, $valid);
122
        }
123 1
        echo PHP_EOL . self::T_BEFORE;
124 1
        $this->error = ($errCount > 0);
125 1
        return $this;
126
    }
127
128
    /**
129
     * exit with non zero exit code if error and blocking mode
130
     *
131
     * @return void
132
     */
133 1
    protected function shutdown(): Checker
134
    {
135 1
        if ($this->error && $this->isBlocking()) {
136
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
137
        }
138 1
        return $this;
139
    }
140
141
    /**
142
     * return formated msg line
143
     *
144
     * @param string $k
145
     * @param float $v
146
     * @return string
147
     */
148 1
    protected function getMsgLine(string $k, float $v, bool $valid): string
149
    {
150 1
        return sprintf(
151 1
            self::MSG_FORMAT,
152 1
            ucfirst($k),
153
            $v,
154 1
            'limit',
155 1
            $this->thresholds[$k],
156 1
            $valid ? self::_OK : self::_KO
157
        );
158
    }
159
160
    /**
161
     * set results
162
     *
163
     * @param integer $coveredClasses
164
     * @param \SimpleXMLElement $metrics
165
     * @return Checker
166
     */
167 1
    protected function setResults(int $coveredClasses, \SimpleXMLElement $metrics): Checker
168
    {
169 1
        $this->results = [
170 1
            Args::_LINES => $this->getElementsRatio($metrics),
171 1
            Args::_METHODS => $this->getMethodsRatio($metrics),
172 1
            Args::_STATEMENTS => $this->getStatementsRatio($metrics),
173 1
            Args::_CLASSES => $this->getClassesRatio(
174 1
                $coveredClasses,
175
                $metrics
176
            )
177
        ];
178 1
        return $this;
179
    }
180
181
    /**
182
     * returns lines coverage ratio as float
183
     *
184
     * @param \SimpleXMLElement $mets
185
     * @return float
186
     */
187 1
    protected function getElementsRatio(\SimpleXMLElement $mets): float
188
    {
189 1
        return isset($mets[self::_ELEMENTS])
190 1
            ? $mets[self::COVERED_ELEMENTS] / $mets[self::_ELEMENTS] * 100
191 1
            : 0;
192
    }
193
194
    /**
195
     * returns methods coverage ratio as float
196
     *
197
     * @param \SimpleXMLElement $mets
198
     * @return float
199
     */
200 1
    protected function getMethodsRatio(\SimpleXMLElement $mets): float
201
    {
202 1
        return isset($mets[Args::_METHODS])
203 1
            ? $mets[self::COVERED_METHODS] / $mets[Args::_METHODS] * 100
204 1
            : 0;
205
    }
206
207
    /**
208
     * returns statements coverage ratio as float
209
     *
210
     * @param \SimpleXMLElement $mets
211
     * @return float
212
     */
213 1
    protected function getStatementsRatio(\SimpleXMLElement $mets): float
214
    {
215 1
        return isset($mets[Args::_STATEMENTS])
216 1
            ? $this->getRatio(
217 1
                (float) $mets[self::COVERED_STATEMENTS],
218 1
                (float) $mets[Args::_STATEMENTS]
219
            )
220 1
            : 0;
221
    }
222
223
    /**
224
     * returns classes coverage ratio as float
225
     *
226
     * @param integer $coveredClasses
227
     * @param \SimpleXMLElement $mets
228
     * @return float
229
     */
230 1
    protected function getClassesRatio(int $coveredClasses, \SimpleXMLElement $mets): float
231
    {
232 1
        return isset($mets[Args::_CLASSES])
233 1
            ? $this->getRatio(
234 1
                (float) $coveredClasses,
235 1
                (float) $mets[Args::_CLASSES]
236
            )
237 1
            : 0;
238
    }
239
240
    /**
241
     * return ratio computation as float
242
     *
243
     * @param float $min
244
     * @param float $max
245
     * @return float
246
     */
247 1
    protected function getRatio(float $min, float $max): float
248
    {
249 1
        return ($min / $max) * 100;
250
    }
251
252
    /**
253
     * set content from file
254
     *
255
     * @return Checker
256
     */
257 1
    protected function setContent(): Checker
258
    {
259 1
        $this->content = ($this->exists())
260
            ? file_get_contents($this->filename)
261 1
            : '';
262 1
        return $this;
263
    }
264
265
    /**
266
     * returns true if file exists
267
     *
268
     * @return boolean
269
     */
270 1
    protected function exists(): bool
271
    {
272 1
        return file_exists($this->filename);
273
    }
274
275
    /**
276
     * return true if blocking option was set
277
     *
278
     * @return boolean
279
     */
280
    protected function isBlocking(): bool
281
    {
282
        return $this->cloverArgs->isBlocking();
283
    }
284
}
285