*
*
*
*
*
*
*
* ```
*
* Note: it is strongly _recommended_ to exclude your test directories for
* select error codes of those particular sniffs instead of relying on this
* property/trait.
*
* @since 0.11.0
* @since 3.0.0 Moved from the Sniff class to this dedicated Trait.
* Renamed from `$custom_test_class_whitelist` to `$custom_test_classes`.
*
* @var string[]
*/
public $custom_test_classes = array();
/**
* List of PHPUnit and WP native classes which test classes can extend.
*
* {internal These are the test cases provided in the `/tests/phpunit/includes/`
* directory of WP Core.}
*
* @since 0.11.0
* @since 3.0.0 - Moved from the Sniff class to this dedicated Trait.
* - Renamed from `$test_class_whitelist` to `$known_test_classes`.
* - Visibility changed from protected to private.
*
* @var array Key is class name, value irrelevant.
*/
private $known_test_classes = array(
// Base test cases.
'WP_UnitTestCase' => true,
'WP_UnitTestCase_Base' => true,
'PHPUnit_Adapter_TestCase' => true,
// Domain specific base test cases.
'WP_Ajax_UnitTestCase' => true,
'WP_Canonical_UnitTestCase' => true,
'WP_Test_REST_Controller_Testcase' => true,
'WP_Test_REST_Post_Type_Controller_Testcase' => true,
'WP_Test_REST_TestCase' => true,
'WP_Test_XML_TestCase' => true,
'WP_XMLRPC_UnitTestCase' => true,
// PHPUnit native test cases.
'PHPUnit_Framework_TestCase' => true,
'PHPUnit\\Framework\\TestCase' => true,
// PHPUnit native TestCase class when imported via use statement.
'TestCase' => true,
);
/**
* Cache of previously added custom test classes.
*
* Prevents having to do the same merges over and over again.
*
* @since 3.0.0
*
* @var string[]
*/
private $added_custom_test_classes = array();
/**
* Combined list of WP/PHPUnit native and custom test classes.
*
* @since 3.0.0
*
* @var array
*/
private $all_test_classes = array();
/**
* Retrieve a list of all registered test classes, both WP/PHPUnit native as well as custom.
*
* @since 3.0.0
*
* @return array
*/
final protected function get_all_test_classes() {
if ( array() === $this->all_test_classes
|| $this->custom_test_classes !== $this->added_custom_test_classes
) {
/*
* Show some tolerance for user input.
* The custom test class names should be passed as FQN without a prefixing `\`.
*/
$custom_test_classes = array();
if ( ! empty( $this->custom_test_classes ) ) {
foreach ( $this->custom_test_classes as $v ) {
$custom_test_classes[] = ltrim( $v, '\\' );
}
}
/*
* Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively.
*/
$custom_test_classes = array_map( 'strtolower', $custom_test_classes );
$known_test_classes = array_change_key_case( $this->known_test_classes, \CASE_LOWER );
$this->all_test_classes = RulesetPropertyHelper::merge_custom_array(
$custom_test_classes,
$known_test_classes
);
// Store the original value so the comparison can succeed.
$this->added_custom_test_classes = $this->custom_test_classes;
}
return $this->all_test_classes;
}
/**
* Check if a class token is part of a unit test suite.
*
* Unit test classes are identified as such:
* - Class which either extends one of the known test cases, such as `WP_UnitTestCase`
* or `PHPUnit_Framework_TestCase` or extends a custom unit test class as listed in the
* `custom_test_classes` property.
*
* @since 0.12.0 Split off from the `is_token_in_test_method()` method.
* @since 1.0.0 Improved recognition of namespaced class names.
* @since 3.0.0 - Moved from the Sniff class to this dedicated Trait.
* - The `$phpcsFile` parameter was added.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @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.
*/
final protected function is_test_class( File $phpcsFile, $stackPtr ) {
$tokens = $phpcsFile->getTokens();
if ( isset( $tokens[ $stackPtr ], Tokens::$ooScopeTokens[ $tokens[ $stackPtr ]['code'] ] ) === false ) {
return false;
}
// Add any potentially extra custom test classes to the known test classes list.
$known_test_classes = $this->get_all_test_classes();
$namespace = strtolower( Namespaces::determineNamespace( $phpcsFile, $stackPtr ) );
// Is the class/trait one of the known test classes ?
$className = ObjectDeclarations::getName( $phpcsFile, $stackPtr );
if ( empty( $className ) === false ) {
$className = strtolower( $className );
if ( '' !== $namespace ) {
if ( isset( $known_test_classes[ $namespace . '\\' . $className ] ) ) {
return true;
}
} elseif ( isset( $known_test_classes[ $className ] ) ) {
return true;
}
}
// Does the class/trait extend one of the known test classes ?
$extendedClassName = ObjectDeclarations::findExtendedClassName( $phpcsFile, $stackPtr );
if ( false === $extendedClassName ) {
return false;
}
$extendedClassName = strtolower( $extendedClassName );
if ( '\\' === $extendedClassName[0] ) {
if ( isset( $known_test_classes[ substr( $extendedClassName, 1 ) ] ) ) {
return true;
}
} elseif ( '' !== $namespace ) {
if ( isset( $known_test_classes[ $namespace . '\\' . $extendedClassName ] ) ) {
return true;
}
} elseif ( isset( $known_test_classes[ $extendedClassName ] ) ) {
return true;
}
/*
* Not examining imported classes via `use` statements as with the variety of syntaxes,
* this would get very complicated.
* After all, users can add an `` for a particular sniff to their
* custom ruleset to selectively exclude the test directory.
*/
return false;
}
}