Test Failed
Pull Request — master (#30)
by Scott
02:49
created

PhpCsLoader::parseLines()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 0
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace exussum12\CoverageChecker;
3
4
use InvalidArgumentException;
5
use PhpParser\Error;
6
use PhpParser\ParserFactory;
7
use stdClass;
8
9
/**
10
 * Class PhpCsLoader
11
 * Used for reading json output from phpcs
12
 * @package exussum12\CoverageChecker
13
 */
14
class PhpCsLoader implements FileChecker
15
{
16
    /**
17
     * @var string
18
     */
19
    protected $json;
20
    /**
21
     * @var array
22
     */
23
    protected $invalidLines;
24
25
    /**
26
     * @var array
27
     */
28
29
    protected $failOnTypes = [
30
        'ERROR',
31
    ];
32
33
    protected $lookupErrorPrefix = [
34
        'Squiz.Commenting.FileComment',
35
        'Squiz.Commenting.ClassComment',
36
        'Squiz.Commenting.FunctionComment',
37
    ];
38
39
    /**
40
     * @var array
41
     */
42
    protected $wholeFileErrors = [
43
        'PSR1.Files.SideEffects.FoundWithSymbols',
44
        'Generic.Files.LineEndings.InvalidEOLChar',
45
    ];
46
47
48
    /**
49
     * @var array
50
     */
51
    protected $invalidFiles = [];
52
53
    /**
54
     * @var array
55
     */
56
    protected $invalidRanges = [];
57
58
59
    /**
60
     * @var FileParser[]
61
     */
62
    protected $parsedFiles = [];
63
64
    /**
65
     * PhpCsLoader constructor.
66
     * @param string $filePath the file path to the json output from phpcs
67
     */
68 View Code Duplication
    public function __construct($filePath)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
69
    {
70
        $this->json = json_decode(file_get_contents($filePath));
71
        if (json_last_error() !== JSON_ERROR_NONE) {
72
            throw new InvalidArgumentException(
73
                "Can't Parse phpcs json - " . json_last_error_msg()
74
            );
75
        }
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function parseLines()
82
    {
83
        $this->invalidLines = [];
84
        foreach ($this->json->files as $fileName => $file) {
85
            foreach ($file->messages as $message) {
86
                $this->addInvalidLine($fileName, $message);
87
            }
88
        }
89
90
        return array_unique(array_merge(
91
            array_keys($this->invalidLines),
92
            array_keys($this->invalidFiles),
93
            array_keys($this->invalidRanges)
94
        ));
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100
    public function getErrorsOnLine($file, $lineNumber)
101
    {
102
        $errors = [];
103
        if (!empty($this->invalidFiles[$file])) {
104
            $errors = $this->invalidFiles[$file];
105
        }
106
107
        if (!empty($this->invalidLines[$file][$lineNumber])) {
108
             $errors = array_merge($errors, $this->invalidLines[$file][$lineNumber]);
109
        }
110
111
        if (!empty($this->invalidRanges[$file])) {
112
            foreach ($this->invalidRanges[$file] as $invalidRange) {
113
                $inRange = $lineNumber >= $invalidRange['from'] &&
114
                    $lineNumber <= $invalidRange['to'];
115
                if ($inRange) {
116
                    $errors[] = $invalidRange['message'];
117
                }
118
            }
119
        }
120
121
        return $errors;
122
    }
123
124
    /**
125
     * @param string $file
126
     * @param stdClass $message
127
     */
128
    protected function addInvalidLine($file, $message)
129
    {
130
        if (!in_array($message->type, $this->failOnTypes)) {
131
            return;
132
        }
133
        $line = $message->line;
134
135
        if ($error = $this->messageStartsWith($message->source, $this->lookupErrorPrefix)) {
136
            $this->handleLookupError($file, $message, $error);
137
            return;
138
        }
139
140
        if (!isset($this->invalidLines[$file][$line])) {
141
            $this->invalidLines[$file][$line] = [];
142
        }
143
144
        $this->invalidLines[$file][$line][] = $message->message;
145
146
        if (in_array($message->source, $this->wholeFileErrors)) {
147
            $this->invalidFiles[$file][] = $message->message;
148
        }
149
    }
150
151
    /**
152
     * @param $message
153
     * @param array $list
154
     * @return bool|string
155
     */
156
    protected function messageStartsWith($message, array $list)
157
    {
158
        foreach ($list as $item) {
159
            if (strpos($message, $item) === 0) {
160
                return $item;
161
            }
162
        }
163
        return false;
164
    }
165
166
    protected function handleLookupError($file, $message, $error)
167
    {
168
        if ($error == 'Squiz.Commenting.FileComment') {
169
            $this->invalidFiles[$file][] = $message->message;
170
        }
171
        $fileParser = $this->getFileParser($file);
172
        $lookup = $this->getMessageRanges($error, $fileParser);
173
174
        $this->addRangeError($file, $lookup, $message);
175
    }
176
177
    protected function getFileParser($filename)
178
    {
179
        if (!isset($this->parsedFiles[$filename])) {
180
            $this->parsedFiles[$filename] = new FileParser(
181
                file_get_contents($filename)
182
            );
183
        }
184
185
        return $this->parsedFiles[$filename];
186
    }
187
188
    /**
189
     * {@inheritdoc}
190
     */
191
    public function handleNotFoundFile()
192
    {
193
        return true;
194
    }
195
196
    /**
197
     * {@inheritdoc}
198
     */
199
    public static function getDescription()
200
    {
201
        return 'Parses the json report format of phpcs, this mode ' .
202
            'only reports errors as violations';
203
    }
204
205
    protected function addRangeError($file, $lookup, $message)
206
    {
207
        $line = $message->line;
208
        foreach ($lookup as $limit) {
209
            if ($line >= $limit->getStartLine() && $line <= $limit->getEndLine()) {
210
                $this->invalidRanges[$file][] = [
211
                    'from' => $limit->getStartLine(),
212
                    'to' => $limit->getEndLine(),
213
                    'message' => $message->message,
214
                ];
215
            }
216
        }
217
    }
218
219
    protected function getMessageRanges($error, $fileParser)
220
    {
221
        if ($error == 'Squiz.Commenting.ClassComment') {
222
            return $fileParser->getClassLimits();
223
        }
224
225
        return $fileParser->getFunctionLimits();
226
    }
227
}
228