Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions WordPress/Sniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -487,16 +487,17 @@ abstract class WordPress_Sniff implements PHP_CodeSniffer_Sniff {
protected $test_class_whitelist = array(
'WP_UnitTestCase' => true,
'PHPUnit_Framework_TestCase' => true,
'PHPUnit\Framework\TestCase' => true,
);

/**
* Custom list of classes which test classes can extend.
*
* 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:
* <rule ref="WordPress.[Subset].[Sniffname]">
Expand Down Expand Up @@ -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
*
Expand All @@ -860,20 +861,46 @@ 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,
$this->test_class_whitelist
);

// 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;
}
Expand Down
39 changes: 19 additions & 20 deletions WordPress/Sniffs/Files/FileNameSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -117,23 +118,22 @@ 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 ) );

/*
* 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',
Expand All @@ -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',
Expand All @@ -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',
Expand All @@ -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().

Expand Down
17 changes: 16 additions & 1 deletion WordPress/Tests/Files/FileNameUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php
// @codingStandardsChangeSetting WordPress.Files.FileName custom_test_class_whitelist My_TestClass
?>

<?php

class TestSample extends My_TestClass {}
// @codingStandardsChangeSetting WordPress.Files.FileName custom_test_class_whitelist false
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

class TestSample extends PHPUnit_Framework_TestCase {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

class TestSample extends PHPUnit\Framework\TestCase {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

class TestSample extends WP_UnitTestCase {}