Failed Conditions
Push — master ( 0d82de...180230 )
by Alexander
02:11
created

TestSuite/AbstractSniffUnitTest.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * An abstract class that all sniff unit tests must extend.
4
 *
5
 * PHP version 5
6
 *
7
 * @category  PHP
8
 * @package   PHP_CodeSniffer
9
 * @author    Greg Sherwood <[email protected]>
10
 * @author    Marc McIntyre <[email protected]>
11
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
12
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
13
 * @link      http://pear.php.net/package/PHP_CodeSniffer
14
 */
15
16
/**
17
 * An abstract class that all sniff unit tests must extend.
18
 *
19
 * A sniff unit test checks a .inc file for expected violations of a single
20
 * coding standard. Expected errors and warnings that are not found, or
21
 * warnings and errors that are not expected, are considered test failures.
22
 *
23
 * @category  PHP
24
 * @package   PHP_CodeSniffer
25
 * @author    Greg Sherwood <[email protected]>
26
 * @author    Marc McIntyre <[email protected]>
27
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
28
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
29
 * @version   Release: @package_version@
30
 * @link      http://pear.php.net/package/PHP_CodeSniffer
31
 */
32
abstract class AbstractSniffUnitTest extends PHPUnit_Framework_TestCase
33
{
34
35
    /**
36
     * The PHP_CodeSniffer object used for testing.
37
     *
38
     * @var PHP_CodeSniffer
39
     */
40
    protected static $phpcs = null;
41
42
43
    /**
44
     * Sets up this unit test.
45
     *
46
     * @return void
47
     */
48
    protected function setUp()
49
    {
50
        if (self::$phpcs === null) {
51
            self::$phpcs = new PHP_CodeSniffer();
52
53
            // Conflicts with Composer AutoLoader.
54
            spl_autoload_unregister(array('PHP_CodeSniffer', 'autoload'));
55
        }
56
57
    }//end setUp()
58
59
60
    /**
61
     * Tests the extending classes Sniff class.
62
     *
63
     * @return void
64
     */
65
    public final function testStandard()
0 ignored issues
show
As per PSR2, final should precede the visibility keyword.
Loading history...
66
    {
67
        // Skip this test if we can't run in this environment.
68
        if ($this->shouldSkipTest() === true) {
69
            $this->markTestSkipped();
70
        }
71
72
        if (method_exists(self::$phpcs, 'initStandard') === true) {
73
            // Only init standard without processing it's files, when possible.
74
            self::$phpcs->initStandard($this->getStandardName(), array($this->getSniffCode()));
75
        } else {
76
            // Init standard and process all it's files.
77
            self::$phpcs->process(array(), $this->getStandardName(), array($this->getSniffCode()));
78
        }
79
80
        self::$phpcs->setIgnorePatterns(array());
81
82
        $failureMessages = array();
83
        $fixingSupported = $this->isFixingSupported();
84
        foreach ($this->_getTestFiles() as $testFile) {
85
            try {
86
                $phpcsFile       = self::$phpcs->processFile($testFile);
87
                $failureMessages = array_merge($failureMessages, $this->generateFailureMessages($phpcsFile));
88
89
                if ($fixingSupported === true && $phpcsFile->getFixableCount() > 0) {
90
                    // Attempt to fix the errors.
91
                    $phpcsFile->fixer->fixFile();
92
                    $fixable = $phpcsFile->getFixableCount();
93
                    if ($fixable > 0) {
94
                        $filename          = basename($testFile);
95
                        $failureMessages[] = "Failed to fix $fixable fixable violations in $filename.";
96
                    } else {
97
                        // Check for a .fixed file to check for accuracy of fixes.
98
                        $fixedFile = $testFile.'.fixed';
99
                        if (file_exists($fixedFile) === true) {
100
                            $diff = $phpcsFile->fixer->generateDiff($fixedFile);
101
                            if (trim($diff) !== '') {
102
                                $filename          = basename($testFile);
103
                                $fixedFilename     = basename($fixedFile);
104
                                $failureMessages[] = "Fixed version of $filename does not match expected version in $fixedFilename; the diff is\n$diff";
105
                            }
106
                        }
107
                    }
108
                }
109
            } catch (Exception $e) {
110
                $this->fail('An unexpected exception has been caught: '.$e->getMessage());
111
            }//end try
112
        }//end foreach
113
114
        if (empty($failureMessages) === false) {
115
            $this->fail(implode(PHP_EOL, $failureMessages));
116
        }
117
118
    }//end testStandard()
119
120
121
    /**
122
     * Determines if used PHPCS version supports fixing.
123
     *
124
     * @return bool
125
     */
126
    protected function isFixingSupported()
127
    {
128
        $classReflection = new \ReflectionClass('PHP_CodeSniffer_File');
129
130
        return $classReflection->hasProperty('fixer');
131
132
    }//end isFixingSupported()
133
134
135
    /**
136
     * Should this test be skipped for some reason.
137
     *
138
     * @return bool
139
     */
140
    protected function shouldSkipTest()
141
    {
142
        return false;
143
144
    }//end shouldSkipTest()
145
146
147
    /**
148
     * The name of the coding standard we are testing.
149
     *
150
     * @return string
151
     */
152
    protected function getStandardName()
153
    {
154
        $basename = $this->getBaseName();
155
156
        return STANDARDS_PATH.DIRECTORY_SEPARATOR.substr($basename, 0, strpos($basename, '_'));
157
158
    }//end getStandardName()
159
160
161
    /**
162
     * The code of the sniff we are testing.
163
     *
164
     * @return string
165
     */
166
    protected function getSniffCode()
167
    {
168
        $parts = explode('_', $this->getBaseName());
169
170
        return $parts[0].'.'.$parts[2].'.'.$parts[3];
171
172
    }//end getSniffCode()
173
174
175
    /**
176
     * Get a list of all test files to check. These will have the same base name
177
     * but different extensions. We ignore the .php file as it is the class.
178
     *
179
     * @return array
180
     */
181
    private function _getTestFiles()
182
    {
183
        // The basis for determining file locations.
184
        $basename = $this->getBaseName();
185
186
        // The name of the dummy file we are testing.
187
        $testFileBase = STANDARDS_PATH.DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $basename).'UnitTest.';
188
189
        $testFiles = array();
190
191
        /** @var SplFileInfo $file */
192
        $directoryIterator = new DirectoryIterator(dirname($testFileBase));
193
194
        foreach ($directoryIterator as $file) {
195
            $path = $file->getPathname();
196
197
            if (substr($path, 0, strlen($testFileBase)) === $testFileBase && $path !== $testFileBase.'php' && $file->getExtension() !== 'fixed') {
198
                $testFiles[] = $path;
199
            }
200
        }
201
202
        // Get them in order.
203
        sort($testFiles);
204
205
        return $testFiles;
206
207
    }//end _getTestFiles()
208
209
210
    /**
211
     * The basis for determining file locations.
212
     *
213
     * @return string
214
     */
215
    protected function getBaseName()
216
    {
217
        return substr(get_class($this), 0, -8);
218
219
    }//end getBaseName()
220
221
222
    /**
223
     * Generate a list of test failures for a given sniffed file.
224
     *
225
     * @param PHP_CodeSniffer_File $file The file being tested.
226
     *
227
     * @return array
228
     * @throws PHP_CodeSniffer_Exception
229
     */
230
    public function generateFailureMessages(PHP_CodeSniffer_File $file)
231
    {
232
        $testFile = $file->getFilename();
233
234
        $foundErrors      = $file->getErrors();
235
        $foundWarnings    = $file->getWarnings();
236
        $expectedErrors   = $this->getErrorList(basename($testFile));
237
        $expectedWarnings = $this->getWarningList(basename($testFile));
238
239
        if (is_array($expectedErrors) === false) {
240
            throw new PHP_CodeSniffer_Exception('getErrorList() must return an array');
241
        }
242
243
        if (is_array($expectedWarnings) === false) {
244
            throw new PHP_CodeSniffer_Exception('getWarningList() must return an array');
245
        }
246
247
        /*
248
            We merge errors and warnings together to make it easier
249
            to iterate over them and produce the errors string. In this way,
250
            we can report on errors and warnings in the same line even though
251
            it's not really structured to allow that.
252
        */
253
254
        $allProblems     = array();
255
        $failureMessages = array();
256
257
        foreach ($foundErrors as $line => $lineErrors) {
258
            foreach ($lineErrors as $column => $errors) {
259
                if (isset($allProblems[$line]) === false) {
260
                    $allProblems[$line] = array(
261
                                           'expected_errors'   => 0,
262
                                           'expected_warnings' => 0,
263
                                           'found_errors'      => array(),
264
                                           'found_warnings'    => array(),
265
                                          );
266
                }
267
268
                $foundErrorsTemp = array();
269
                foreach ($allProblems[$line]['found_errors'] as $foundError) {
270
                    $foundErrorsTemp[] = $foundError;
271
                }
272
273
                $errorsTemp = array();
274
                foreach ($errors as $foundError) {
275
                    $errorsTemp[] = $foundError['message'].' ('.$foundError['source'].')';
276
                }
277
278
                $allProblems[$line]['found_errors'] = array_merge($foundErrorsTemp, $errorsTemp);
279
            }//end foreach
280
281
            if (isset($expectedErrors[$line]) === true) {
282
                $allProblems[$line]['expected_errors'] = $expectedErrors[$line];
283
            } else {
284
                $allProblems[$line]['expected_errors'] = 0;
285
            }
286
287
            unset($expectedErrors[$line]);
288
        }//end foreach
289
290
        foreach ($expectedErrors as $line => $numErrors) {
291
            if (isset($allProblems[$line]) === false) {
292
                $allProblems[$line] = array(
293
                                       'expected_errors'   => 0,
294
                                       'expected_warnings' => 0,
295
                                       'found_errors'      => array(),
296
                                       'found_warnings'    => array(),
297
                                      );
298
            }
299
300
            $allProblems[$line]['expected_errors'] = $numErrors;
301
        }
302
303
        foreach ($foundWarnings as $line => $lineWarnings) {
304
            foreach ($lineWarnings as $column => $warnings) {
305
                if (isset($allProblems[$line]) === false) {
306
                    $allProblems[$line] = array(
307
                                           'expected_errors'   => 0,
308
                                           'expected_warnings' => 0,
309
                                           'found_errors'      => array(),
310
                                           'found_warnings'    => array(),
311
                                          );
312
                }
313
314
                $foundWarningsTemp = array();
315
                foreach ($allProblems[$line]['found_warnings'] as $foundWarning) {
316
                    $foundWarningsTemp[] = $foundWarning;
317
                }
318
319
                $warningsTemp = array();
320
                foreach ($warnings as $warning) {
321
                    $warningsTemp[] = $warning['message'].' ('.$warning['source'].')';
322
                }
323
324
                $allProblems[$line]['found_warnings'] = array_merge($foundWarningsTemp, $warningsTemp);
325
            }//end foreach
326
327
            if (isset($expectedWarnings[$line]) === true) {
328
                $allProblems[$line]['expected_warnings'] = $expectedWarnings[$line];
329
            } else {
330
                $allProblems[$line]['expected_warnings'] = 0;
331
            }
332
333
            unset($expectedWarnings[$line]);
334
        }//end foreach
335
336
        foreach ($expectedWarnings as $line => $numWarnings) {
337
            if (isset($allProblems[$line]) === false) {
338
                $allProblems[$line] = array(
339
                                       'expected_errors'   => 0,
340
                                       'expected_warnings' => 0,
341
                                       'found_errors'      => array(),
342
                                       'found_warnings'    => array(),
343
                                      );
344
            }
345
346
            $allProblems[$line]['expected_warnings'] = $numWarnings;
347
        }
348
349
        // Order the messages by line number.
350
        ksort($allProblems);
351
352
        foreach ($allProblems as $line => $problems) {
353
            $numErrors        = count($problems['found_errors']);
354
            $numWarnings      = count($problems['found_warnings']);
355
            $expectedErrors   = $problems['expected_errors'];
356
            $expectedWarnings = $problems['expected_warnings'];
357
358
            $errors      = '';
359
            $foundString = '';
360
361
            if ($expectedErrors !== $numErrors || $expectedWarnings !== $numWarnings) {
362
                $lineMessage     = "[LINE $line]";
363
                $expectedMessage = 'Expected ';
364
                $foundMessage    = 'in '.basename($testFile).' but found ';
365
366
                if ($expectedErrors !== $numErrors) {
367
                    $expectedMessage .= "$expectedErrors error(s)";
368
                    $foundMessage    .= "$numErrors error(s)";
369
                    if ($numErrors !== 0) {
370
                        $foundString .= 'error(s)';
371
                        $errors      .= implode(PHP_EOL.' -> ', $problems['found_errors']);
372
                    }
373
374
                    if ($expectedWarnings !== $numWarnings) {
375
                        $expectedMessage .= ' and ';
376
                        $foundMessage    .= ' and ';
377
                        if ($numWarnings !== 0) {
378
                            if ($foundString !== '') {
379
                                $foundString .= ' and ';
380
                            }
381
                        }
382
                    }
383
                }
384
385
                if ($expectedWarnings !== $numWarnings) {
386
                    $expectedMessage .= "$expectedWarnings warning(s)";
387
                    $foundMessage    .= "$numWarnings warning(s)";
388
                    if ($numWarnings !== 0) {
389
                        $foundString .= 'warning(s)';
390
                        if (empty($errors) === false) {
391
                            $errors .= PHP_EOL.' -> ';
392
                        }
393
394
                        $errors .= implode(PHP_EOL.' -> ', $problems['found_warnings']);
395
                    }
396
                }
397
398
                $fullMessage = "$lineMessage $expectedMessage $foundMessage.";
399
                if ($errors !== '') {
400
                    $fullMessage .= " The $foundString found were:".PHP_EOL." -> $errors";
401
                }
402
403
                $failureMessages[] = $fullMessage;
404
            }//end if
405
        }//end foreach
406
407
        return $failureMessages;
408
409
    }//end generateFailureMessages()
410
411
412
    /**
413
     * Returns the lines where errors should occur.
414
     *
415
     * The key of the array should represent the line number and the value
416
     * should represent the number of errors that should occur on that line.
417
     *
418
     * @param string $testFile Name of the file with test data.
419
     *
420
     * @return array(int => int)
421
     */
422
    protected abstract function getErrorList($testFile);
0 ignored issues
show
The abstract declaration must precede the visibility declaration
Loading history...
423
424
425
    /**
426
     * Returns the lines where warnings should occur.
427
     *
428
     * The key of the array should represent the line number and the value
429
     * should represent the number of warnings that should occur on that line.
430
     *
431
     * @param string $testFile Name of the file with test data.
432
     *
433
     * @return array(int => int)
434
     */
435
    protected abstract function getWarningList($testFile);
0 ignored issues
show
The abstract declaration must precede the visibility declaration
Loading history...
436
437
438
}//end class
439