Subversion Repositories Applications.framework

Rev

Rev 5 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 aurelien 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 <gsherwood@squiz.net>
10
 * @author    Marc McIntyre <mmcintyre@squiz.net>
11
 * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
12
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
34 aurelien 13
 * @version   CVS: $Id: AbstractSniffUnitTest.php 34 2009-04-09 07:34:39Z aurelien $
5 aurelien 14
 * @link      http://pear.php.net/package/PHP_CodeSniffer
15
 */
16
 
17
require_once 'PHPUnit/Framework/TestCase.php';
18
 
19
/**
20
 * An abstract class that all sniff unit tests must extend.
21
 *
22
 * A sniff unit test checks a .inc file for expected violations of a single
23
 * coding standard. Expected errors and warnings that are not found, or
24
 * warnings and errors that are not expected, are considered test failures.
25
 *
26
 * @category  PHP
27
 * @package   PHP_CodeSniffer
28
 * @author    Greg Sherwood <gsherwood@squiz.net>
29
 * @author    Marc McIntyre <mmcintyre@squiz.net>
30
 * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
31
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
32
 * @version   Release: 1.2.0RC1
33
 * @link      http://pear.php.net/package/PHP_CodeSniffer
34
 */
35
abstract class AbstractSniffUnitTest extends PHPUnit_Framework_TestCase
36
{
37
 
38
    /**
39
     * The PHP_CodeSniffer object used for testing.
40
     *
41
     * @var PHP_CodeSniffer
42
     */
43
    protected static $phpcs = null;
44
 
45
 
46
    /**
47
     * Sets up this unit test.
48
     *
49
     * @return void
50
     */
51
    protected function setUp()
52
    {
53
        if (self::$phpcs === null) {
54
            self::$phpcs = new PHP_CodeSniffer();
55
        }
56
 
57
    }//end setUp()
58
 
59
 
60
    /**
61
     * Should this test be skipped for some reason.
62
     *
63
     * @return void
64
     */
65
    protected function shouldSkipTest()
66
    {
67
        return false;
68
 
69
    }//end shouldSkipTest()
70
 
71
 
72
    /**
73
     * Tests the extending classes Sniff class.
74
     *
75
     * @return void
76
     * @throws PHPUnit_Framework_Error
77
     */
78
    protected final function runTest()
79
    {
80
        // Skip this test if we can't run in this environment.
81
        if ($this->shouldSkipTest() === true) {
82
            $this->markTestSkipped();
83
        }
84
 
85
        // The basis for determining file locations.
86
        $basename = substr(get_class($this), 0, -8);
87
 
88
        // The name of the coding standard we are testing.
89
        $standardName = substr($basename, 0, strpos($basename, '_'));
90
 
91
        // The class name of the sniff we are testing.
92
        $sniffClass = str_replace('_Tests_', '_Sniffs_', $basename).'Sniff';
93
 
94
        if (is_file(dirname(__FILE__).'/../../CodeSniffer.php') === true) {
95
            // We have not been installed.
96
            $standardsDir = realpath(dirname(__FILE__).'/../../CodeSniffer/Standards');
97
            $testFileBase = $standardsDir.'/'.str_replace('_', '/', $basename).'UnitTest.';
98
        } else {
99
            // The name of the dummy file we are testing.
100
            $testFileBase = dirname(__FILE__).'/'.str_replace('_', '/', $basename).'UnitTest.';
101
        }
102
 
103
        // Get a list of all test files to check. These will have the same base
104
        // name but different extensions. We ignore the .php file as it is the
105
        // class.
106
        $testFiles = array();
107
 
108
        $dir = substr($testFileBase, 0, strrpos($testFileBase, '/'));
109
        $di  = new DirectoryIterator($dir);
110
 
111
        foreach ($di as $file) {
112
            $path = $file->getPathname();
113
            if (substr($path, 0, strlen($testFileBase)) === $testFileBase) {
114
                if ($path !== $testFileBase.'php') {
115
                    $testFiles[] = $path;
116
                }
117
            }
118
        }
119
 
120
        // Get them in order. This is particularly important for multi-file sniffs.
121
        sort($testFiles);
122
 
123
        $failureMessages = array();
124
        $multiFileSniff  = false;
125
        foreach ($testFiles as $testFile) {
126
            try {
127
                self::$phpcs->process($testFile, $standardName, array($sniffClass));
128
            } catch (Exception $e) {
129
                $this->fail('An unexpected exception has been caught: '.$e->getMessage());
130
            }
131
 
132
            // After processing a file, check if the sniff was actually
133
            // a multi-file sniff (i.e., had no indivdual file sniffs).
134
            // If it is, we can skip checking of the other files and
135
            // do a single multi-file check.
136
            $sniffs = self::$phpcs->getTokenSniffs();
137
            if (empty($sniffs['file']) === true) {
138
                $multiFileSniff = true;
139
                break;
140
            }
141
 
142
            $files = self::$phpcs->getFiles();
143
            $file  = array_pop($files);
144
 
145
            $failures = $this->generateFailureMessages($file, $testFile);
146
            $failureMessages = array_merge($failureMessages, $failures);
147
        }//end foreach
148
 
149
        if ($multiFileSniff === true) {
150
            try {
151
                self::$phpcs->process($testFiles, $standardName, array($sniffClass));
152
            } catch (Exception $e) {
153
                $this->fail('An unexpected exception has been caught: '.$e->getMessage());
154
            }
155
 
156
            $files = self::$phpcs->getFiles();
157
            foreach ($files as $file) {
158
                $failures = $this->generateFailureMessages($file);
159
                $failureMessages = array_merge($failureMessages, $failures);
160
            }
161
        }
162
 
163
        if (empty($failureMessages) === false) {
164
            $this->fail(implode(PHP_EOL, $failureMessages));
165
        }
166
 
167
    }//end testSniff()
168
 
169
 
170
    /**
171
     * Generate a list of test failures for a given sniffed file.
172
     *
173
     * @return array
174
     * @throws PHP_CodeSniffer_Exception
175
     */
176
    public function generateFailureMessages($file)
177
    {
178
        $testFile = $file->getFilename();
179
 
180
        $foundErrors      = $file->getErrors();
181
        $foundWarnings    = $file->getWarnings();
182
        $expectedErrors   = $this->getErrorList(basename($testFile));
183
        $expectedWarnings = $this->getWarningList(basename($testFile));
184
 
185
        if (is_array($expectedErrors) === false) {
186
            throw new PHP_CodeSniffer_Exception('getErrorList() must return an array');
187
        }
188
 
189
        if (is_array($expectedWarnings) === false) {
190
            throw new PHP_CodeSniffer_Exception('getWarningList() must return an array');
191
        }
192
 
193
        /*
194
         We merge errors and warnings together to make it easier
195
         to iterate over them and produce the errors string. In this way,
196
         we can report on errors and warnings in the same line even though
197
         it's not really structured to allow that.
198
        */
199
 
200
        $allProblems     = array();
201
        $failureMessages = array();
202
 
203
        foreach ($foundErrors as $line => $lineErrors) {
204
            foreach ($lineErrors as $column => $errors) {
205
                if (isset($allProblems[$line]) === false) {
206
                    $allProblems[$line] = array(
207
                                           'expected_errors'   => 0,
208
                                           'expected_warnings' => 0,
209
                                           'found_errors'      => array(),
210
                                           'found_warnings'    => array(),
211
                                          );
212
                }
213
 
214
                $foundErrorsTemp = array();
215
                foreach ($allProblems[$line]['found_errors'] as $foundError) {
216
                    $foundErrorsTemp[] = $foundError['message'];
217
                }
218
 
219
                $errorsTemp = array();
220
                foreach ($errors as $foundError) {
221
                    $errorsTemp[] = $foundError['message'];
222
                }
223
 
224
                $allProblems[$line]['found_errors'] = array_merge($foundErrorsTemp, $errorsTemp);
225
            }
226
 
227
            if (isset($expectedErrors[$line]) === true) {
228
                $allProblems[$line]['expected_errors'] = $expectedErrors[$line];
229
            } else {
230
                $allProblems[$line]['expected_errors'] = 0;
231
            }
232
 
233
            unset($expectedErrors[$line]);
234
        }//end foreach
235
 
236
        foreach ($expectedErrors as $line => $numErrors) {
237
            if (isset($allProblems[$line]) === false) {
238
                $allProblems[$line] = array(
239
                                       'expected_errors'   => 0,
240
                                       'expected_warnings' => 0,
241
                                       'found_errors'      => array(),
242
                                       'found_warnings'    => array(),
243
                                      );
244
            }
245
 
246
            $allProblems[$line]['expected_errors'] = $numErrors;
247
        }
248
 
249
        foreach ($foundWarnings as $line => $lineWarnings) {
250
            foreach ($lineWarnings as $column => $warnings) {
251
                if (isset($allProblems[$line]) === false) {
252
                    $allProblems[$line] = array(
253
                                           'expected_errors'   => 0,
254
                                           'expected_warnings' => 0,
255
                                           'found_errors'      => array(),
256
                                           'found_warnings'    => array(),
257
                                          );
258
                }
259
 
260
                $warningsTemp = array();
261
                foreach ($warnings as $warning) {
262
                    $warningsTemp[] = $warning['message'];
263
                }
264
 
265
                $allProblems[$line]['found_warnings'] = $warningsTemp;
266
            }
267
 
268
            if (isset($expectedWarnings[$line]) === true) {
269
                $allProblems[$line]['expected_warnings'] = $expectedWarnings[$line];
270
            } else {
271
                $allProblems[$line]['expected_warnings'] = 0;
272
            }
273
 
274
            unset($expectedWarnings[$line]);
275
        }//end foreach
276
 
277
        foreach ($expectedWarnings as $line => $numWarnings) {
278
            if (isset($allProblems[$line]) === false) {
279
                $allProblems[$line] = array(
280
                                       'expected_errors'   => 0,
281
                                       'expected_warnings' => 0,
282
                                       'found_errors'      => array(),
283
                                       'found_warnings'    => array(),
284
                                      );
285
            }
286
 
287
            $allProblems[$line]['expected_warnings'] = $numWarnings;
288
        }
289
 
290
        // Order the messages by line number.
291
        ksort($allProblems);
292
 
293
        foreach ($allProblems as $line => $problems) {
294
            $numErrors        = count($problems['found_errors']);
295
            $numWarnings      = count($problems['found_warnings']);
296
            $expectedErrors   = $problems['expected_errors'];
297
            $expectedWarnings = $problems['expected_warnings'];
298
 
299
            $errors      = '';
300
            $foundString = '';
301
 
302
            if ($expectedErrors !== $numErrors || $expectedWarnings !== $numWarnings) {
303
                $lineMessage     = "[LINE $line]";
304
                $expectedMessage = 'Expected ';
305
                $foundMessage    = 'in '.basename($testFile).' but found ';
306
 
307
                if ($expectedErrors !== $numErrors) {
308
                    $expectedMessage .= "$expectedErrors error(s)";
309
                    $foundMessage    .= "$numErrors error(s)";
310
                    if ($numErrors !== 0) {
311
                        $foundString .= 'error(s)';
312
                        $errors      .= implode(PHP_EOL.' -> ', $problems['found_errors']);
313
                    }
314
 
315
                    if ($expectedWarnings !== $numWarnings) {
316
                        $expectedMessage .= ' and ';
317
                        $foundMessage    .= ' and ';
318
                        if ($numWarnings !== 0) {
319
                            if ($foundString !== '') {
320
                                $foundString .= ' and ';
321
                            }
322
                        }
323
                    }
324
                }
325
 
326
                if ($expectedWarnings !== $numWarnings) {
327
                    $expectedMessage .= "$expectedWarnings warning(s)";
328
                    $foundMessage    .= "$numWarnings warning(s)";
329
                    if ($numWarnings !== 0) {
330
                        $foundString .= 'warning(s)';
331
                        if (empty($errors) === false) {
332
                            $errors .= PHP_EOL.' -> ';
333
                        }
334
 
335
                        $errors .= implode(PHP_EOL.' -> ', $problems['found_warnings']);
336
                    }
337
                }
338
 
339
                $fullMessage = "$lineMessage $expectedMessage $foundMessage.";
340
                if ($errors !== '') {
341
                    $fullMessage .= " The $foundString found were:".PHP_EOL." -> $errors";
342
                }
343
 
344
                $failureMessages[] = $fullMessage;
345
            }//end if
346
        }//end foreach
347
 
348
        return $failureMessages;
349
 
350
    }//end generateFailureMessages()
351
 
352
 
353
    /**
354
     * Returns the lines where errors should occur.
355
     *
356
     * The key of the array should represent the line number and the value
357
     * should represent the number of errors that should occur on that line.
358
     *
359
     * @return array(int => int)
360
     */
361
    protected abstract function getErrorList();
362
 
363
 
364
    /**
365
     * Returns the lines where warnings should occur.
366
     *
367
     * The key of the array should represent the line number and the value
368
     * should represent the number of warnings that should occur on that line.
369
     *
370
     * @return array(int => int)
371
     */
372
    protected abstract function getWarningList();
373
 
374
 
375
}//end class
376
 
377
?>