diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 355c6a4558..926f28e8c1 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -487,6 +487,7 @@ abstract class WordPress_Sniff implements PHP_CodeSniffer_Sniff { protected $test_class_whitelist = array( 'WP_UnitTestCase' => true, 'PHPUnit_Framework_TestCase' => true, + 'PHPUnit\Framework\TestCase' => true, ); /** @@ -494,9 +495,9 @@ abstract class WordPress_Sniff implements PHP_CodeSniffer_Sniff { * * This property allows end-users to add to the $test_class_whitelist via their ruleset. * This property will need to be set for each sniff which uses the - * `is_token_in_test_method()` method. - * Currently the method is only used by the `WordPress.Variables.GlobalVariables` - * sniff. + * `is_test_class()` method. + * Currently the method is used by the `WordPress.Variables.GlobalVariables` + * and the `WordPress.Files.Filename` sniffs. * * Example usage: * @@ -833,7 +834,7 @@ protected function has_whitelist_comment( $comment, $stackPtr ) { * * Unit test methods are identified as such: * - Method name starts with `test_`. - * - Method is within a class which either extends WP_UnitTestCase or PHPUnit_Framework_TestCase. + * - Method is within a unit test class. * * @since 0.11.0 * @@ -860,6 +861,32 @@ protected function is_token_in_test_method( $stackPtr ) { $structureToken = $traitToken; } + return $this->is_test_class( $structureToken ); + } + + + /** + * Check if a class token is part of a unit test suite. + * + * Unit test classes are identified as such: + * - Class which either extends WP_UnitTestCase or PHPUnit_Framework_TestCase + * or a custom whitelisted unit test class. + * + * @since 0.12.0 Split off from the `is_token_in_test_method()` method. + * + * @param int $stackPtr The position of the token to be examined. + * This should be a class, anonymous class or trait token. + * + * @return bool True if the class is a unit test class, false otherwise. + */ + protected function is_test_class( $stackPtr ) { + + if ( ! isset( $this->tokens[ $stackPtr ] ) + || in_array( $this->tokens[ $stackPtr ]['type'], array( 'T_CLASS', 'T_ANON_CLASS', 'T_TRAIT' ), true ) === false + ) { + return false; + } + // Add any potentially whitelisted custom test classes to the whitelist. $whitelist = $this->merge_custom_array( $this->custom_test_class_whitelist, @@ -867,13 +894,13 @@ protected function is_token_in_test_method( $stackPtr ) { ); // Is the class/trait one of the whitelisted test classes ? - $className = $this->phpcsFile->getDeclarationName( $structureToken ); + $className = $this->phpcsFile->getDeclarationName( $stackPtr ); if ( isset( $whitelist[ $className ] ) ) { return true; } // Does the class/trait extend one of the whitelisted test classes ? - $extendedClassName = $this->phpcsFile->findExtendedClassName( $structureToken ); + $extendedClassName = $this->phpcsFile->findExtendedClassName( $stackPtr ); if ( isset( $whitelist[ $extendedClassName ] ) ) { return true; } diff --git a/WordPress/Sniffs/Files/FileNameSniff.php b/WordPress/Sniffs/Files/FileNameSniff.php index 4a46162338..a521845ed8 100644 --- a/WordPress/Sniffs/Files/FileNameSniff.php +++ b/WordPress/Sniffs/Files/FileNameSniff.php @@ -21,8 +21,9 @@ * template tags end in `-template`. Based on @subpackage file DocBlock tag. * - This sniff will now allow for underscores in file names for certain theme * specific exceptions if the `$is_theme` property is set to `true`. + * @since 0.12.0 - Now extends the `WordPress_Sniff` class. */ -class WordPress_Sniffs_Files_FileNameSniff implements PHP_CodeSniffer_Sniff { +class WordPress_Sniffs_Files_FileNameSniff extends WordPress_Sniff { /** * Regex for the theme specific exceptions. @@ -117,15 +118,14 @@ public function register() { /** * Processes this test, when one of its tokens is encountered. * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. + * @param int $stackPtr The position of the current token in the stack. * - * @return int + * @return int|void Integer stack pointer to skip forward or void to continue + * normal file processing. */ - public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) { + public function process_token( $stackPtr ) { - $file = $phpcsFile->getFileName(); + $file = $this->phpcsFile->getFileName(); $fileName = basename( $file ); $expected = strtolower( str_replace( '_', '-', $fileName ) ); @@ -133,7 +133,7 @@ public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) { * Generic check for lowercase hyphenated file names. */ if ( $fileName !== $expected && ( false === $this->is_theme || 1 !== preg_match( self::THEME_EXCEPTIONS_REGEX, $fileName ) ) ) { - $phpcsFile->addError( + $this->phpcsFile->addError( 'Filenames should be all lowercase with hyphens as word separators. Expected %s, but found %s.', 0, 'NotHyphenatedLowercase', @@ -147,13 +147,13 @@ public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) { * the file name reflects the class name. */ if ( true === $this->strict_class_file_names ) { - $has_class = $phpcsFile->findNext( T_CLASS, $stackPtr ); - if ( false !== $has_class ) { - $class_name = $phpcsFile->getDeclarationName( $has_class ); + $has_class = $this->phpcsFile->findNext( T_CLASS, $stackPtr ); + if ( false !== $has_class && false === $this->is_test_class( $has_class ) ) { + $class_name = $this->phpcsFile->getDeclarationName( $has_class ); $expected = 'class-' . strtolower( str_replace( '_', '-', $class_name ) ); if ( substr( $fileName, 0, -4 ) !== $expected && ! isset( $this->class_exceptions[ $fileName ] ) ) { - $phpcsFile->addError( + $this->phpcsFile->addError( 'Class file names should be based on the class name with "class-" prepended. Expected %s, but found %s.', 0, 'InvalidClassFileName', @@ -171,21 +171,20 @@ public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) { * Check non-class files in "wp-includes" with a "@subpackage Template" tag for a "-template" suffix. */ if ( false !== strpos( $file, DIRECTORY_SEPARATOR . 'wp-includes' . DIRECTORY_SEPARATOR ) ) { - $subpackage_tag = $phpcsFile->findNext( T_DOC_COMMENT_TAG, $stackPtr, null, false, '@subpackage' ); + $subpackage_tag = $this->phpcsFile->findNext( T_DOC_COMMENT_TAG, $stackPtr, null, false, '@subpackage' ); if ( false !== $subpackage_tag ) { - $subpackage = $phpcsFile->findNext( T_DOC_COMMENT_STRING, $subpackage_tag ); + $subpackage = $this->phpcsFile->findNext( T_DOC_COMMENT_STRING, $subpackage_tag ); if ( false !== $subpackage ) { - $tokens = $phpcsFile->getTokens(); $fileName_end = substr( $fileName, -13 ); - $has_class = $phpcsFile->findNext( T_CLASS, $stackPtr ); + $has_class = $this->phpcsFile->findNext( T_CLASS, $stackPtr ); - if ( ( 'Template' === trim( $tokens[ $subpackage ]['content'] ) - && $tokens[ $subpackage_tag ]['line'] === $tokens[ $subpackage ]['line'] ) + if ( ( 'Template' === trim( $this->tokens[ $subpackage ]['content'] ) + && $this->tokens[ $subpackage_tag ]['line'] === $this->tokens[ $subpackage ]['line'] ) && ( ( ! defined( 'PHP_CODESNIFFER_IN_TESTS' ) && '-template.php' !== $fileName_end ) || ( defined( 'PHP_CODESNIFFER_IN_TESTS' ) && '-template.inc' !== $fileName_end ) ) && false === $has_class ) { - $phpcsFile->addError( + $this->phpcsFile->addError( 'Files containing template tags should have "-template" appended to the end of the file name. Expected %s, but found %s.', 0, 'InvalidTemplateTagFileName', @@ -200,7 +199,7 @@ public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) { } // End if(). // Only run this sniff once per file, no need to run it again. - return ( $phpcsFile->numTokens + 1 ); + return ( $this->phpcsFile->numTokens + 1 ); } // End process(). diff --git a/WordPress/Tests/Files/FileNameUnitTest.php b/WordPress/Tests/Files/FileNameUnitTest.php index 3751ad6c13..ce1364d0eb 100644 --- a/WordPress/Tests/Files/FileNameUnitTest.php +++ b/WordPress/Tests/Files/FileNameUnitTest.php @@ -48,6 +48,16 @@ class WordPress_Tests_Files_FileNameUnitTest extends AbstractSniffUnitTest { // Non-strict class names still have to comply with lowercase hyphenated. 'ClassNonStrictClass.inc' => 1, + /* + * In /FileNameUnitTests/TestFiles. + */ + 'test-sample-phpunit.inc' => 0, + 'test-sample-phpunit6.inc' => 0, + 'test-sample-wpunit.inc' => 0, + // @todo Fix this! False positive, custom property setting not recognized. + // Is issue with unit tests, not with the sniff. If the property is set from the ruleset, it "should" work. + 'test-sample-custom-unit.inc' => 1, + /* * In /FileNameUnitTests/ThemeExceptions. */ @@ -81,7 +91,12 @@ class WordPress_Tests_Files_FileNameUnitTest extends AbstractSniffUnitTest { */ protected function getTestFiles( $testFileBase ) { $sep = DIRECTORY_SEPARATOR; - $test_files = glob( dirname( $testFileBase ) . $sep . 'FileNameUnitTests{' . $sep . ',' . $sep . 'ThemeExceptions' . $sep . ',' . $sep . 'wp-includes' . $sep . '}*.inc', GLOB_BRACE ); + $test_files = glob( dirname( $testFileBase ) . $sep . 'FileNameUnitTests{' . $sep . ',' . $sep . 'TestFiles' . $sep . ',' . $sep . 'ThemeExceptions' . $sep . ',' . $sep . 'wp-includes' . $sep . '}*.inc', GLOB_BRACE ); + + // Adjust the expected results array for PHP 5.2 as PHP 5.2 does not recognize namespaces. + if ( PHP_VERSION_ID < 50300 ) { + $this->expected_results['test-sample-phpunit6.inc'] = 1; + } if ( ! empty( $test_files ) ) { return $test_files; diff --git a/WordPress/Tests/Files/FileNameUnitTests/TestFiles/test-sample-custom-unit.inc b/WordPress/Tests/Files/FileNameUnitTests/TestFiles/test-sample-custom-unit.inc new file mode 100644 index 0000000000..cc4901a70b --- /dev/null +++ b/WordPress/Tests/Files/FileNameUnitTests/TestFiles/test-sample-custom-unit.inc @@ -0,0 +1,8 @@ + + +