Mercurial > hg > isophonics-drupal-site
comparison vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php @ 17:129ea1e6d783
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:21:36 +0000 |
parents | |
children | af1871eacc83 |
comparison
equal
deleted
inserted
replaced
16:c2387f117808 | 17:129ea1e6d783 |
---|---|
1 <?php | |
2 /** | |
3 * An abstract class that all sniff unit tests must extend. | |
4 * | |
5 * A sniff unit test checks a .inc file for expected violations of a single | |
6 * coding standard. Expected errors and warnings that are not found, or | |
7 * warnings and errors that are not expected, are considered test failures. | |
8 * | |
9 * @author Greg Sherwood <gsherwood@squiz.net> | |
10 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) | |
11 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence | |
12 */ | |
13 | |
14 namespace PHP_CodeSniffer\Tests\Standards; | |
15 | |
16 use PHP_CodeSniffer\Config; | |
17 use PHP_CodeSniffer\Exceptions\RuntimeException; | |
18 use PHP_CodeSniffer\Ruleset; | |
19 use PHP_CodeSniffer\Files\LocalFile; | |
20 use PHP_CodeSniffer\Util\Common; | |
21 use PHPUnit\Framework\TestCase; | |
22 | |
23 abstract class AbstractSniffUnitTest extends TestCase | |
24 { | |
25 | |
26 /** | |
27 * Enable or disable the backup and restoration of the $GLOBALS array. | |
28 * Overwrite this attribute in a child class of TestCase. | |
29 * Setting this attribute in setUp() has no effect! | |
30 * | |
31 * @var boolean | |
32 */ | |
33 protected $backupGlobals = false; | |
34 | |
35 /** | |
36 * The path to the standard's main directory. | |
37 * | |
38 * @var string | |
39 */ | |
40 public $standardsDir = null; | |
41 | |
42 /** | |
43 * The path to the standard's test directory. | |
44 * | |
45 * @var string | |
46 */ | |
47 public $testsDir = null; | |
48 | |
49 | |
50 /** | |
51 * Sets up this unit test. | |
52 * | |
53 * @return void | |
54 */ | |
55 protected function setUp() | |
56 { | |
57 $class = get_class($this); | |
58 $this->standardsDir = $GLOBALS['PHP_CODESNIFFER_STANDARD_DIRS'][$class]; | |
59 $this->testsDir = $GLOBALS['PHP_CODESNIFFER_TEST_DIRS'][$class]; | |
60 | |
61 }//end setUp() | |
62 | |
63 | |
64 /** | |
65 * Get a list of all test files to check. | |
66 * | |
67 * These will have the same base as the sniff name but different extensions. | |
68 * We ignore the .php file as it is the class. | |
69 * | |
70 * @param string $testFileBase The base path that the unit tests files will have. | |
71 * | |
72 * @return string[] | |
73 */ | |
74 protected function getTestFiles($testFileBase) | |
75 { | |
76 $testFiles = []; | |
77 | |
78 $dir = substr($testFileBase, 0, strrpos($testFileBase, DIRECTORY_SEPARATOR)); | |
79 $di = new \DirectoryIterator($dir); | |
80 | |
81 foreach ($di as $file) { | |
82 $path = $file->getPathname(); | |
83 if (substr($path, 0, strlen($testFileBase)) === $testFileBase) { | |
84 if ($path !== $testFileBase.'php' && substr($path, -5) !== 'fixed' && substr($path, -4) !== '.bak') { | |
85 $testFiles[] = $path; | |
86 } | |
87 } | |
88 } | |
89 | |
90 // Put them in order. | |
91 sort($testFiles); | |
92 | |
93 return $testFiles; | |
94 | |
95 }//end getTestFiles() | |
96 | |
97 | |
98 /** | |
99 * Should this test be skipped for some reason. | |
100 * | |
101 * @return boolean | |
102 */ | |
103 protected function shouldSkipTest() | |
104 { | |
105 return false; | |
106 | |
107 }//end shouldSkipTest() | |
108 | |
109 | |
110 /** | |
111 * Tests the extending classes Sniff class. | |
112 * | |
113 * @return void | |
114 * @throws \PHPUnit\Framework\Exception | |
115 */ | |
116 final public function testSniff() | |
117 { | |
118 // Skip this test if we can't run in this environment. | |
119 if ($this->shouldSkipTest() === true) { | |
120 $this->markTestSkipped(); | |
121 } | |
122 | |
123 $sniffCode = Common::getSniffCode(get_class($this)); | |
124 list($standardName, $categoryName, $sniffName) = explode('.', $sniffCode); | |
125 | |
126 $testFileBase = $this->testsDir.$categoryName.DIRECTORY_SEPARATOR.$sniffName.'UnitTest.'; | |
127 | |
128 // Get a list of all test files to check. | |
129 $testFiles = $this->getTestFiles($testFileBase); | |
130 $GLOBALS['PHP_CODESNIFFER_SNIFF_CASE_FILES'][] = $testFiles; | |
131 | |
132 if (isset($GLOBALS['PHP_CODESNIFFER_CONFIG']) === true) { | |
133 $config = $GLOBALS['PHP_CODESNIFFER_CONFIG']; | |
134 } else { | |
135 $config = new Config(); | |
136 $config->cache = false; | |
137 $GLOBALS['PHP_CODESNIFFER_CONFIG'] = $config; | |
138 } | |
139 | |
140 $config->standards = [$standardName]; | |
141 $config->sniffs = [$sniffCode]; | |
142 $config->ignored = []; | |
143 | |
144 if (isset($GLOBALS['PHP_CODESNIFFER_RULESETS']) === false) { | |
145 $GLOBALS['PHP_CODESNIFFER_RULESETS'] = []; | |
146 } | |
147 | |
148 if (isset($GLOBALS['PHP_CODESNIFFER_RULESETS'][$standardName]) === false) { | |
149 $ruleset = new Ruleset($config); | |
150 $GLOBALS['PHP_CODESNIFFER_RULESETS'][$standardName] = $ruleset; | |
151 } | |
152 | |
153 $ruleset = $GLOBALS['PHP_CODESNIFFER_RULESETS'][$standardName]; | |
154 | |
155 $sniffFile = $this->standardsDir.DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR.$categoryName.DIRECTORY_SEPARATOR.$sniffName.'Sniff.php'; | |
156 | |
157 $sniffClassName = substr(get_class($this), 0, -8).'Sniff'; | |
158 $sniffClassName = str_replace('\Tests\\', '\Sniffs\\', $sniffClassName); | |
159 $sniffClassName = Common::cleanSniffClass($sniffClassName); | |
160 | |
161 $restrictions = [strtolower($sniffClassName) => true]; | |
162 $ruleset->registerSniffs([$sniffFile], $restrictions, []); | |
163 $ruleset->populateTokenListeners(); | |
164 | |
165 $failureMessages = []; | |
166 foreach ($testFiles as $testFile) { | |
167 $filename = basename($testFile); | |
168 $oldConfig = $config->getSettings(); | |
169 | |
170 try { | |
171 $this->setCliValues($filename, $config); | |
172 $phpcsFile = new LocalFile($testFile, $ruleset, $config); | |
173 $phpcsFile->process(); | |
174 } catch (RuntimeException $e) { | |
175 $this->fail('An unexpected exception has been caught: '.$e->getMessage()); | |
176 } | |
177 | |
178 $failures = $this->generateFailureMessages($phpcsFile); | |
179 $failureMessages = array_merge($failureMessages, $failures); | |
180 | |
181 if ($phpcsFile->getFixableCount() > 0) { | |
182 // Attempt to fix the errors. | |
183 $phpcsFile->fixer->fixFile(); | |
184 $fixable = $phpcsFile->getFixableCount(); | |
185 if ($fixable > 0) { | |
186 $failureMessages[] = "Failed to fix $fixable fixable violations in $filename"; | |
187 } | |
188 | |
189 // Check for a .fixed file to check for accuracy of fixes. | |
190 $fixedFile = $testFile.'.fixed'; | |
191 if (file_exists($fixedFile) === true) { | |
192 $diff = $phpcsFile->fixer->generateDiff($fixedFile); | |
193 if (trim($diff) !== '') { | |
194 $filename = basename($testFile); | |
195 $fixedFilename = basename($fixedFile); | |
196 $failureMessages[] = "Fixed version of $filename does not match expected version in $fixedFilename; the diff is\n$diff"; | |
197 } | |
198 } | |
199 } | |
200 | |
201 // Restore the config. | |
202 $config->setSettings($oldConfig); | |
203 }//end foreach | |
204 | |
205 if (empty($failureMessages) === false) { | |
206 $this->fail(implode(PHP_EOL, $failureMessages)); | |
207 } | |
208 | |
209 }//end testSniff() | |
210 | |
211 | |
212 /** | |
213 * Generate a list of test failures for a given sniffed file. | |
214 * | |
215 * @param \PHP_CodeSniffer\Files\LocalFile $file The file being tested. | |
216 * | |
217 * @return array | |
218 * @throws \PHP_CodeSniffer\Exceptions\RuntimeException | |
219 */ | |
220 public function generateFailureMessages(LocalFile $file) | |
221 { | |
222 $testFile = $file->getFilename(); | |
223 | |
224 $foundErrors = $file->getErrors(); | |
225 $foundWarnings = $file->getWarnings(); | |
226 $expectedErrors = $this->getErrorList(basename($testFile)); | |
227 $expectedWarnings = $this->getWarningList(basename($testFile)); | |
228 | |
229 if (is_array($expectedErrors) === false) { | |
230 throw new RuntimeException('getErrorList() must return an array'); | |
231 } | |
232 | |
233 if (is_array($expectedWarnings) === false) { | |
234 throw new RuntimeException('getWarningList() must return an array'); | |
235 } | |
236 | |
237 /* | |
238 We merge errors and warnings together to make it easier | |
239 to iterate over them and produce the errors string. In this way, | |
240 we can report on errors and warnings in the same line even though | |
241 it's not really structured to allow that. | |
242 */ | |
243 | |
244 $allProblems = []; | |
245 $failureMessages = []; | |
246 | |
247 foreach ($foundErrors as $line => $lineErrors) { | |
248 foreach ($lineErrors as $column => $errors) { | |
249 if (isset($allProblems[$line]) === false) { | |
250 $allProblems[$line] = [ | |
251 'expected_errors' => 0, | |
252 'expected_warnings' => 0, | |
253 'found_errors' => [], | |
254 'found_warnings' => [], | |
255 ]; | |
256 } | |
257 | |
258 $foundErrorsTemp = []; | |
259 foreach ($allProblems[$line]['found_errors'] as $foundError) { | |
260 $foundErrorsTemp[] = $foundError; | |
261 } | |
262 | |
263 $errorsTemp = []; | |
264 foreach ($errors as $foundError) { | |
265 $errorsTemp[] = $foundError['message'].' ('.$foundError['source'].')'; | |
266 | |
267 $source = $foundError['source']; | |
268 if (in_array($source, $GLOBALS['PHP_CODESNIFFER_SNIFF_CODES']) === false) { | |
269 $GLOBALS['PHP_CODESNIFFER_SNIFF_CODES'][] = $source; | |
270 } | |
271 | |
272 if ($foundError['fixable'] === true | |
273 && in_array($source, $GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES']) === false | |
274 ) { | |
275 $GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES'][] = $source; | |
276 } | |
277 } | |
278 | |
279 $allProblems[$line]['found_errors'] = array_merge($foundErrorsTemp, $errorsTemp); | |
280 }//end foreach | |
281 | |
282 if (isset($expectedErrors[$line]) === true) { | |
283 $allProblems[$line]['expected_errors'] = $expectedErrors[$line]; | |
284 } else { | |
285 $allProblems[$line]['expected_errors'] = 0; | |
286 } | |
287 | |
288 unset($expectedErrors[$line]); | |
289 }//end foreach | |
290 | |
291 foreach ($expectedErrors as $line => $numErrors) { | |
292 if (isset($allProblems[$line]) === false) { | |
293 $allProblems[$line] = [ | |
294 'expected_errors' => 0, | |
295 'expected_warnings' => 0, | |
296 'found_errors' => [], | |
297 'found_warnings' => [], | |
298 ]; | |
299 } | |
300 | |
301 $allProblems[$line]['expected_errors'] = $numErrors; | |
302 } | |
303 | |
304 foreach ($foundWarnings as $line => $lineWarnings) { | |
305 foreach ($lineWarnings as $column => $warnings) { | |
306 if (isset($allProblems[$line]) === false) { | |
307 $allProblems[$line] = [ | |
308 'expected_errors' => 0, | |
309 'expected_warnings' => 0, | |
310 'found_errors' => [], | |
311 'found_warnings' => [], | |
312 ]; | |
313 } | |
314 | |
315 $foundWarningsTemp = []; | |
316 foreach ($allProblems[$line]['found_warnings'] as $foundWarning) { | |
317 $foundWarningsTemp[] = $foundWarning; | |
318 } | |
319 | |
320 $warningsTemp = []; | |
321 foreach ($warnings as $warning) { | |
322 $warningsTemp[] = $warning['message'].' ('.$warning['source'].')'; | |
323 } | |
324 | |
325 $allProblems[$line]['found_warnings'] = array_merge($foundWarningsTemp, $warningsTemp); | |
326 }//end foreach | |
327 | |
328 if (isset($expectedWarnings[$line]) === true) { | |
329 $allProblems[$line]['expected_warnings'] = $expectedWarnings[$line]; | |
330 } else { | |
331 $allProblems[$line]['expected_warnings'] = 0; | |
332 } | |
333 | |
334 unset($expectedWarnings[$line]); | |
335 }//end foreach | |
336 | |
337 foreach ($expectedWarnings as $line => $numWarnings) { | |
338 if (isset($allProblems[$line]) === false) { | |
339 $allProblems[$line] = [ | |
340 'expected_errors' => 0, | |
341 'expected_warnings' => 0, | |
342 'found_errors' => [], | |
343 'found_warnings' => [], | |
344 ]; | |
345 } | |
346 | |
347 $allProblems[$line]['expected_warnings'] = $numWarnings; | |
348 } | |
349 | |
350 // Order the messages by line number. | |
351 ksort($allProblems); | |
352 | |
353 foreach ($allProblems as $line => $problems) { | |
354 $numErrors = count($problems['found_errors']); | |
355 $numWarnings = count($problems['found_warnings']); | |
356 $expectedErrors = $problems['expected_errors']; | |
357 $expectedWarnings = $problems['expected_warnings']; | |
358 | |
359 $errors = ''; | |
360 $foundString = ''; | |
361 | |
362 if ($expectedErrors !== $numErrors || $expectedWarnings !== $numWarnings) { | |
363 $lineMessage = "[LINE $line]"; | |
364 $expectedMessage = 'Expected '; | |
365 $foundMessage = 'in '.basename($testFile).' but found '; | |
366 | |
367 if ($expectedErrors !== $numErrors) { | |
368 $expectedMessage .= "$expectedErrors error(s)"; | |
369 $foundMessage .= "$numErrors error(s)"; | |
370 if ($numErrors !== 0) { | |
371 $foundString .= 'error(s)'; | |
372 $errors .= implode(PHP_EOL.' -> ', $problems['found_errors']); | |
373 } | |
374 | |
375 if ($expectedWarnings !== $numWarnings) { | |
376 $expectedMessage .= ' and '; | |
377 $foundMessage .= ' and '; | |
378 if ($numWarnings !== 0) { | |
379 if ($foundString !== '') { | |
380 $foundString .= ' and '; | |
381 } | |
382 } | |
383 } | |
384 } | |
385 | |
386 if ($expectedWarnings !== $numWarnings) { | |
387 $expectedMessage .= "$expectedWarnings warning(s)"; | |
388 $foundMessage .= "$numWarnings warning(s)"; | |
389 if ($numWarnings !== 0) { | |
390 $foundString .= 'warning(s)'; | |
391 if (empty($errors) === false) { | |
392 $errors .= PHP_EOL.' -> '; | |
393 } | |
394 | |
395 $errors .= implode(PHP_EOL.' -> ', $problems['found_warnings']); | |
396 } | |
397 } | |
398 | |
399 $fullMessage = "$lineMessage $expectedMessage $foundMessage."; | |
400 if ($errors !== '') { | |
401 $fullMessage .= " The $foundString found were:".PHP_EOL." -> $errors"; | |
402 } | |
403 | |
404 $failureMessages[] = $fullMessage; | |
405 }//end if | |
406 }//end foreach | |
407 | |
408 return $failureMessages; | |
409 | |
410 }//end generateFailureMessages() | |
411 | |
412 | |
413 /** | |
414 * Get a list of CLI values to set before the file is tested. | |
415 * | |
416 * @param string $filename The name of the file being tested. | |
417 * @param \PHP_CodeSniffer\Config $config The config data for the run. | |
418 * | |
419 * @return void | |
420 */ | |
421 public function setCliValues($filename, $config) | |
422 { | |
423 return; | |
424 | |
425 }//end setCliValues() | |
426 | |
427 | |
428 /** | |
429 * Returns the lines where errors should occur. | |
430 * | |
431 * The key of the array should represent the line number and the value | |
432 * should represent the number of errors that should occur on that line. | |
433 * | |
434 * @return array<int, int> | |
435 */ | |
436 abstract protected function getErrorList(); | |
437 | |
438 | |
439 /** | |
440 * Returns the lines where warnings should occur. | |
441 * | |
442 * The key of the array should represent the line number and the value | |
443 * should represent the number of warnings that should occur on that line. | |
444 * | |
445 * @return array<int, int> | |
446 */ | |
447 abstract protected function getWarningList(); | |
448 | |
449 | |
450 }//end class |