From 02b03ddf2c19a5bae97716078c9a828cfa75c914 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Nov 2023 05:09:57 +0100 Subject: [PATCH] NamingConventions/NamespaceName: add support for strict PSR-4 compliance checking As the Yoast plugin test directories will start to follow PSR-4. the `NamespaceName` sniff will need to be able to enforce this. This commit adds this ability to the sniff. Notes: * It adds a new `public` `psr4_paths` ruleset property via the `PSR4PathsTrait` utility. * If the file being examined is in a path indicated as a PSR-4 path, PSR-4 based namespace names will be enforced. The differences between the "old-style" enforcement and PSR-4 are in case-sensitivity and in how characters which are allowed in paths, but not allowed in namespace names are handled. * Includes updated error message/code for the "missing prefix" check when the file is in a PSR-4 path. * Includes updated/adjusted logic for the "not counting of `Tests`/`Doubles`" directories as the `Tests` may be part of the PSR-4 namespace. Also note that when both a `psr4_paths` as well as the `src_directory` and `prefixes` properties are set, the `psr4_paths` property will take precedence and the sniff will only fall back to the previous logic if the file is not in a path matching one of the PSR-4 directories. Includes ample tests for this new functionality. Includes updated XML documentation. Includes updating the YoastCS native PHPCS ruleset to indicate that the YoastCS repo follows PSR-4 (as per the PHPCS file name rules). Note: if the name in use in the file is causing a problematic parse error (like in the test with the `#` in the namespace name), the sniff will stay silent. This is the normal behaviour for a PHPCS check when encountering parse errors. :point_right: The sniff changes are probably easiest to review while ignoring whitespace. --- .phpcs.xml.dist | 7 +- .../NamespaceNameStandard.xml | 28 ++- .../NamingConventions/NamespaceNameSniff.php | 188 +++++++++++++----- .../NamespaceNameUnitTest.php | 94 +++++++++ ...h-translation-src-deeper-than-psr4-sub.inc | 22 ++ ...translation-psr4-case-sensitive-proper.inc | 74 +++++++ ...-translation-psr4-case-sensitive-lower.inc | 14 ++ .../PSR4_Path/path-translation-psr4.inc | 78 ++++++++ .../sub path/path-translation-psr4-space.inc | 12 ++ .../sub#path/path-translation-psr4-hash.inc | 12 ++ .../sub-path/path-translation-psr4-dash.inc | 12 ++ .../sub.path/path-translation-psr4-dot.inc | 12 ++ .../NamespaceNameUnitTests/no-basepath.inc | 51 +++++ 13 files changed, 544 insertions(+), 60 deletions(-) create mode 100644 Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/ProperCase/SubPath/path-translation-src-deeper-than-psr4-sub.inc create mode 100644 Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/ProperCase/path-translation-psr4-case-sensitive-proper.inc create mode 100644 Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/lowercase/path-translation-psr4-case-sensitive-lower.inc create mode 100644 Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/path-translation-psr4.inc create mode 100644 Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub path/path-translation-psr4-space.inc create mode 100644 Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub#path/path-translation-psr4-hash.inc create mode 100644 Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub-path/path-translation-psr4-dash.inc create mode 100644 Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub.path/path-translation-psr4-dot.inc diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 5e48d56e..fb90a0ec 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -79,11 +79,8 @@ - - - - - + + diff --git a/Yoast/Docs/NamingConventions/NamespaceNameStandard.xml b/Yoast/Docs/NamingConventions/NamespaceNameStandard.xml index 50d595bc..be5f3bf0 100644 --- a/Yoast/Docs/NamingConventions/NamespaceNameStandard.xml +++ b/Yoast/Docs/NamingConventions/NamespaceNameStandard.xml @@ -50,10 +50,18 @@ namespace Yoast\WP\Plugin\Tests\Foo\Bar\Flo\Sub; @@ -72,4 +80,20 @@ namespace Yoast\WP\Plugin\Unrelated; ]]> + + + User_Forms/file.php --> +User_Forms; + ]]> + + + User_forms/file.php --> +user_Forms; + ]]> + + diff --git a/Yoast/Sniffs/NamingConventions/NamespaceNameSniff.php b/Yoast/Sniffs/NamingConventions/NamespaceNameSniff.php index e7373646..293aff39 100644 --- a/Yoast/Sniffs/NamingConventions/NamespaceNameSniff.php +++ b/Yoast/Sniffs/NamingConventions/NamespaceNameSniff.php @@ -10,6 +10,7 @@ use YoastCS\Yoast\Utils\CustomPrefixesTrait; use YoastCS\Yoast\Utils\PathHelper; use YoastCS\Yoast\Utils\PathValidationHelper; +use YoastCS\Yoast\Utils\PSR4PathsTrait; /** * Check namespace name declarations. @@ -23,13 +24,16 @@ * placed in. * * @since 2.0.0 - * @since 3.0.0 Added new check to verify a prefix is used. + * @since 3.0.0 - Added new check to verify a prefix is used. + * - The sniff now also has the ability to check for PSR-4 compliant namespace names. * * @uses \YoastCS\Yoast\Utils\CustomPrefixesTrait::$prefixes + * @uses \YoastCS\Yoast\Utils\PSR4PathsTrait::$psr4_paths */ final class NamespaceNameSniff implements Sniff { use CustomPrefixesTrait; + use PSR4PathsTrait; /** * Double/Mock/Fixture directories to allow for. @@ -135,14 +139,42 @@ public function process( File $phpcsFile, $stackPtr ) { return; } - $this->validate_prefixes(); + // Stripping potential quotes to ensure `stdin_path` passed by IDEs does not include quotes. + $file = TextStrings::stripQuotes( $phpcsFile->getFileName() ); + if ( $file === 'STDIN' ) { + $file = ''; // @codeCoverageIgnore + } + else { + $file = PathHelper::normalize_absolute_path( $file ); + } + + $valid_prefixes = []; + $psr4_info = false; + if ( $file !== '' ) { + $psr4_info = $this->get_psr4_info( $phpcsFile, $file ); + } + + if ( \is_array( $psr4_info ) ) { + // If a PSR4 path matched, there will only ever be one valid prefix for the matched path. + $valid_prefixes = [ $psr4_info['prefix'] . '\\' ]; + } + else { + // Safeguard that the PSR-4 prefixes are always included. + // Makes sure level depth check still happens even if there is no basepath or path doesn't match PSR-4 path. + if ( empty( $this->prefixes ) && ! empty( $this->psr4_paths ) ) { + $this->prefixes = \array_keys( $this->psr4_paths ); + } + + $this->validate_prefixes(); + $valid_prefixes = $this->validated_prefixes; + } // Strip off the (longest) plugin prefix. $namespace_name_no_prefix = $namespace_name; $found_prefix = ''; - if ( ! empty( $this->validated_prefixes ) ) { + if ( ! empty( $valid_prefixes ) ) { $name = $namespace_name . '\\'; // Validated prefixes always have a \ at the end. - foreach ( $this->validated_prefixes as $prefix ) { + foreach ( $valid_prefixes as $prefix ) { if ( \strpos( $name, $prefix ) === 0 ) { $namespace_name_no_prefix = \rtrim( \substr( $name, \strlen( $prefix ) ), '\\' ); $found_prefix = \rtrim( $prefix, '\\' ); @@ -153,19 +185,31 @@ public function process( File $phpcsFile, $stackPtr ) { } // Check if a prefix is used. - if ( ! empty( $this->validated_prefixes ) && $found_prefix === '' ) { - if ( \count( $this->validated_prefixes ) === 1 ) { - $error = 'A namespace name is required to start with the "%s" prefix.'; + if ( ! empty( $valid_prefixes ) && $found_prefix === '' ) { + $prefixes = $valid_prefixes; + + if ( $psr4_info !== false ) { + $error = 'PSR-4 namespace name for this path is required to start with the "%1$s" prefix.'; + $errorcode = 'MissingPSR4Prefix'; } else { - $error = 'A namespace name is required to start with one of the following prefixes: "%s"'; + $error = 'A namespace name is required to start with one of the following prefixes: "%s"'; + $errorcode = 'MissingPrefix'; + + $prefixes = \array_merge( $prefixes, \array_keys( $this->psr4_paths ) ); + $prefixes = \array_unique( $prefixes ); + + if ( \count( $prefixes ) === 1 ) { + $error = 'A namespace name is required to start with the "%s" prefix.'; + } + else { + \natcasesort( $prefixes ); + } } - $prefixes = $this->validated_prefixes; - \natcasesort( $prefixes ); $data = [ \implode( '", "', $prefixes ) ]; - $phpcsFile->addError( $error, $stackPtr, 'MissingPrefix', $data ); + $phpcsFile->addError( $error, $stackPtr, $errorcode, $data ); } /* @@ -175,8 +219,9 @@ public function process( File $phpcsFile, $stackPtr ) { $namespace_for_level_check = $namespace_name_no_prefix; // Allow for a variation of `Tests\` and `Tests\*\Doubles\` after the prefix. - $starts_with_tests = ( \strpos( $namespace_for_level_check, 'Tests\\' ) === 0 ); - if ( $starts_with_tests === true ) { + $starts_with_tests = ( \strpos( $namespace_for_level_check, 'Tests\\' ) === 0 ); + $prefix_ends_with_tests = ( \substr( $found_prefix, -6 ) === '\Tests' ); + if ( $starts_with_tests === true || $prefix_ends_with_tests === true ) { $stripped = false; foreach ( self::DOUBLE_DIRS as $dir => $length ) { if ( \strpos( $namespace_for_level_check, $dir ) !== false ) { @@ -187,16 +232,27 @@ public function process( File $phpcsFile, $stackPtr ) { } if ( $stripped === false ) { - // No double dir found, now check/strip typical test dirs. - if ( \strpos( $namespace_for_level_check, 'Tests\WP\\' ) === 0 ) { - $namespace_for_level_check = \substr( $namespace_for_level_check, 9 ); - } - elseif ( \strpos( $namespace_for_level_check, 'Tests\Unit\\' ) === 0 ) { - $namespace_for_level_check = \substr( $namespace_for_level_check, 11 ); + if ( $starts_with_tests === true ) { + // No double dir found, now check/strip typical test dirs. + if ( \strpos( $namespace_for_level_check, 'Tests\WP\\' ) === 0 ) { + $namespace_for_level_check = \substr( $namespace_for_level_check, 9 ); + } + elseif ( \strpos( $namespace_for_level_check, 'Tests\Unit\\' ) === 0 ) { + $namespace_for_level_check = \substr( $namespace_for_level_check, 11 ); + } + else { + // Okay, so this only has the `Tests` prefix, just strip it. + $namespace_for_level_check = \substr( $namespace_for_level_check, 6 ); + } } - else { - // Okay, so this only has the `Tests` prefix, just strip it. - $namespace_for_level_check = \substr( $namespace_for_level_check, 6 ); + elseif ( $prefix_ends_with_tests === true ) { + // Prefix which already includes `Tests`. + if ( \strpos( $namespace_for_level_check, 'WP\\' ) === 0 ) { + $namespace_for_level_check = \substr( $namespace_for_level_check, 3 ); + } + elseif ( \strpos( $namespace_for_level_check, 'Unit\\' ) === 0 ) { + $namespace_for_level_check = \substr( $namespace_for_level_check, 5 ); + } } } } @@ -237,40 +293,50 @@ public function process( File $phpcsFile, $stackPtr ) { return; } - // Stripping potential quotes to ensure `stdin_path` passed by IDEs does not include quotes. - $file = TextStrings::stripQuotes( $phpcsFile->getFileName() ); - if ( $file === 'STDIN' ) { + if ( $file === '' ) { + // STDIN. return; // @codeCoverageIgnore } - $directory = PathHelper::normalize_absolute_path( \dirname( $file ) ); $relative_directory = ''; + if ( \is_array( $psr4_info ) ) { + $relative_directory = $psr4_info['relative']; + } + else { + $directory = PathHelper::normalize_absolute_path( \dirname( $file ) ); - $this->validate_src_directory( $phpcsFile ); + $this->validate_src_directory( $phpcsFile ); - if ( empty( $this->validated_src_directory ) === false ) { - foreach ( $this->validated_src_directory as $absolute_src_path ) { - if ( PathHelper::path_starts_with( $directory, $absolute_src_path ) === false ) { - continue; - } + if ( empty( $this->validated_src_directory ) === false ) { + foreach ( $this->validated_src_directory as $absolute_src_path ) { + if ( PathHelper::path_starts_with( $directory, $absolute_src_path ) === false ) { + continue; + } - $relative_directory = PathHelper::strip_basepath( $directory, $absolute_src_path ); - if ( $relative_directory === '.' ) { - $relative_directory = ''; + $relative_directory = PathHelper::strip_basepath( $directory, $absolute_src_path ); + break; } - break; } } + if ( $relative_directory === '.' ) { + $relative_directory = ''; + } + // Now any potential src directory has been stripped, remove surrounding slashes. $relative_directory = \trim( $relative_directory, '/' ); + // Directory to namespace translation. $expected = '[Plugin\Prefix]'; if ( $found_prefix !== '' ) { $expected = $found_prefix; } - elseif ( \count( $this->validated_prefixes ) === 1 ) { - $expected = \rtrim( $this->validated_prefixes[0], '\\' ); + // Namespace name doesn't have the correct prefix, but we do know what the prefix should be. + elseif ( \is_array( $psr4_info ) ) { + $expected = $psr4_info['prefix']; + } + elseif ( \count( $valid_prefixes ) === 1 ) { + $expected = \rtrim( $valid_prefixes[0], '\\' ); } $clean = []; @@ -281,10 +347,13 @@ public function process( File $phpcsFile, $stackPtr ) { $levels = \array_filter( $levels ); // Remove empties, just in case. foreach ( $levels as $level ) { - $cleaned_level = \preg_replace( '`[[:punct:]]`', '_', $level ); - $words = \explode( '_', $cleaned_level ); - $words = \array_map( 'ucfirst', $words ); - $cleaned_level = \implode( '_', $words ); + $cleaned_level = $level; + if ( $psr4_info === false ) { + $cleaned_level = \preg_replace( '`[[:punct:]]`', '_', $cleaned_level ); + $words = \explode( '_', $cleaned_level ); + $words = \array_map( 'ucfirst', $words ); + $cleaned_level = \implode( '_', $words ); + } if ( NamingConventions::isValidIdentifierName( $cleaned_level ) === false ) { $phpcsFile->addError( @@ -304,23 +373,36 @@ public function process( File $phpcsFile, $stackPtr ) { $name_for_compare = \implode( '\\', $clean ); } - if ( \strcasecmp( $name_for_compare, $namespace_name_no_prefix ) === 0 ) { - return; + // Check whether the namespace name complies with the rules. + if ( $psr4_info !== false ) { + // Check for PSR-4 compliant namespace. + if ( \strcmp( $name_for_compare, $namespace_name_no_prefix ) === 0 ) { + return; + } + + $error = 'Directory marked as a PSR-4 path. The namespace name should match the path exactly in a case-sensitive manner. Expected namespace name: "%s"; found: "%s"'; + $code = 'NotPSR4Compliant'; + } + else { + // Check for "old-style" namespace. + if ( \strcasecmp( $name_for_compare, $namespace_name_no_prefix ) === 0 ) { + return; + } + + $error = 'The namespace (sub)level(s) should reflect the directory path to the file. Expected: "%s"; Found: "%s"'; + $code = 'Invalid'; } if ( $name_for_compare !== '' ) { $expected .= '\\' . $name_for_compare; } - $phpcsFile->addError( - 'The namespace (sub)level(s) should reflect the directory path to the file. Expected: "%s"; Found: "%s"', - $stackPtr, - 'Invalid', - [ - $expected, - $namespace_name, - ] - ); + $data = [ + $expected, + $namespace_name, + ]; + + $phpcsFile->addError( $error, $stackPtr, $code, $data ); } /** diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTest.php b/Yoast/Tests/NamingConventions/NamespaceNameUnitTest.php index 453d10ea..a2add417 100644 --- a/Yoast/Tests/NamingConventions/NamespaceNameUnitTest.php +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTest.php @@ -171,6 +171,75 @@ public function getErrorList( string $testFile = '' ): array { 14 => 1, ]; + // Path translation with $psr4_paths set tests. + case 'path-translation-psr4.inc': + return [ + 11 => 2, + 12 => 2, + 21 => 2, + 22 => 1, + 23 => 1, + 33 => 2, + 34 => 2, + 35 => 1, + 36 => 1, + 37 => 1, + 53 => 2, + 54 => 2, + 70 => 2, + 71 => 2, + 72 => 2, + 73 => 2, + ]; + + case 'path-translation-psr4-case-sensitive-lower.inc': + return [ + 11 => 1, + ]; + + case 'path-translation-psr4-case-sensitive-proper.inc': + return [ + 12 => 3, + 13 => 2, + 14 => 1, + 15 => 1, + 16 => 1, + 26 => 2, + 27 => 2, + 28 => 1, + 29 => 1, + 39 => 3, + 40 => 2, + 41 => 1, + 42 => 1, + 52 => 2, + 53 => 2, + 54 => 3, + 55 => 1, + 56 => 1, + 66 => 2, + 67 => 3, + 68 => 1, + 69 => 1, + ]; + + case 'path-translation-src-deeper-than-psr4-sub.inc': + return [ + 13 => 1, + 14 => 1, + 15 => 1, + 16 => 3, + 17 => 3, + ]; + + // PSR4 path translation with unconventional chars in directory name. + case 'path-translation-psr4-dash.inc': + case 'path-translation-psr4-dot.inc': + case 'path-translation-psr4-space.inc': + return [ + 1 => 1, // Invalid dir error. + ]; + // Path translation with no matching $src_directory. case 'path-translation-mismatch.inc': return [ @@ -214,6 +283,22 @@ public function getWarningList( string $testFile = '' ): array { 127 => 1, 128 => 1, 129 => 1, + 147 => 1, + 148 => 1, + 149 => 1, + 150 => 1, + 151 => 1, + 152 => 1, + 153 => 1, + 154 => 1, + 172 => 1, + 173 => 1, + 174 => 1, + 175 => 1, + 176 => 1, + 177 => 1, + 178 => 1, + 179 => 1, ]; case 'no-basepath-scoped.inc': @@ -226,6 +311,15 @@ public function getWarningList( string $testFile = '' ): array { 14 => 1, ]; + case 'path-translation-psr4-case-sensitive-proper.inc': + return [ + 13 => 1, + 27 => 1, + 40 => 1, + 53 => 1, + 66 => 1, + ]; + default: return []; } diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/ProperCase/SubPath/path-translation-src-deeper-than-psr4-sub.inc b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/ProperCase/SubPath/path-translation-src-deeper-than-psr4-sub.inc new file mode 100644 index 00000000..8b1c5c4e --- /dev/null +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/ProperCase/SubPath/path-translation-src-deeper-than-psr4-sub.inc @@ -0,0 +1,22 @@ +PSR4_Path + */ + +namespace Prefix\ProperCase\SubPath; // Error. + +namespace Prefix\SubPath; // Error. +namespace Prefix\ProperCase\Subpath; // Error. +namespace Prefix\ProperCase\subpath; // Error. +namespace Yoast\WP\Plugin\SubPath; // Error. +namespace Yoast\WP\Plugin\PSR4_Path\ProperCase\SubPath; // Error. + +// Reset to default settings. +// phpcs:set Yoast.NamingConventions.NamespaceName prefixes[] +// phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] +// phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/ProperCase/path-translation-psr4-case-sensitive-proper.inc b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/ProperCase/path-translation-psr4-case-sensitive-proper.inc new file mode 100644 index 00000000..81cf6293 --- /dev/null +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/ProperCase/path-translation-psr4-case-sensitive-proper.inc @@ -0,0 +1,74 @@ +PSR4_Path + */ +namespace Yoast\WP\Plugin\ProperCase; // OK. + +namespace Yoast\Plugin\PSR4_Path\ProperCase; // Error x 3. +namespace Yoast\Plugin\ProperCase; // Error x 2 + warning. +namespace Yoast\WP\Plugin\propercase; // Error. +namespace Yoast\WP\Plugin\Propercase; // Error. +namespace Yoast\WP\Plugin\PROPERCASE; // Error. + +/* + * Testing that PSR-4 path translation takes precedence over src_directory [1]. + * + * @phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] PSR4_Path/ProperCase + * @phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] Yoast\WP\Plugin=>PSR4_Path + */ +namespace Yoast\WP\Plugin\ProperCase; // OK. + +namespace Yoast\Plugin; // Error x 2. +namespace Yoast\Plugin\ProperCase; // Error x 2 + warning. +namespace Yoast\WP\Plugin; // Error. +namespace Yoast\WP\Plugin\PSR4_Path\ProperCase; // Error. + +/* + * Testing that PSR-4 path translation takes precedence over src_directory [2]. + * + * @phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] PSR4_Path + * @phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] Yoast\WP\Plugin\\=>. + */ +namespace Yoast\WP\Plugin\PSR4_Path\ProperCase; // OK. + +namespace Yoast\Plugin\PSR4_Path\ProperCase; // Error x 3. +namespace Yoast\Plugin\ProperCase; // Error x 2 + warning. +namespace Yoast\WP\Plugin; // Error. +namespace Yoast\WP\Plugin\ProperCase; // Error. + +/* + * Testing that PSR-4 path translation takes precedence over src_directory [3]. + * + * phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] PSR4_Path + * phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] Yoast\WP\Plugin=>PSR4_Path/ProperCase + */ +namespace Yoast\WP\Plugin; // OK. + +namespace Yoast\Plugin; // Error x 2. +namespace Yoast\Plugin\ProperCase; // Error x 2 + warning. +namespace Yoast\Plugin\PSR4_Path\ProperCase; // Error x 3. +namespace Yoast\WP\Plugin\ProperCase; // Error. +namespace Yoast\WP\Plugin\PSR4_Path\ProperCase; // Error. + +/* + * Testing that PSR-4 path translation takes precedence over src_directory [4]. + * + * phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] . + * phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] Yoast\WP\Plugin\\=>PSR4_Path/ + */ +namespace Yoast\WP\Plugin\ProperCase; // OK. + +namespace Yoast\Plugin\ProperCase; // Error x 2 + warning. +namespace Yoast\Plugin\PSR4_Path\ProperCase; // Error x 3. +namespace Yoast\WP\Plugin; // Error. +namespace Yoast\WP\Plugin\PSR4_Path\ProperCase; // Error. + +// Reset to default settings. +// phpcs:set Yoast.NamingConventions.NamespaceName prefixes[] +// phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] +// phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/lowercase/path-translation-psr4-case-sensitive-lower.inc b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/lowercase/path-translation-psr4-case-sensitive-lower.inc new file mode 100644 index 00000000..f9221d38 --- /dev/null +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/lowercase/path-translation-psr4-case-sensitive-lower.inc @@ -0,0 +1,14 @@ +PSR4_Path + */ + +namespace Yoast\WP\Plugin\lowercase; // OK. + +namespace Yoast\WP\Plugin\Lowercase; // Error. + +// Reset to default settings. +// phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/path-translation-psr4.inc b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/path-translation-psr4.inc new file mode 100644 index 00000000..8c9a05ca --- /dev/null +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/path-translation-psr4.inc @@ -0,0 +1,78 @@ +PSR4_Path + */ +namespace PSR4_Path; // OK. + +// PSR-4 names are case-sensitive. +namespace psr4_Path; // Error x 2. +namespace Psr4_PATH; // Error x 2. + +/* + * Testing path translation in combination with psr4_paths, no src directory, no prefixes. + * + * phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] PrefixA\\=>PSR4_Path,PrefixB\\=>OtherPath + */ +namespace PrefixA; // OK. + +namespace PrefixB; // Error x 2. +namespace PrefixA\PSR4_PATH; // Error. +namespace PrefixA\Psr4_path; // Error. + +/* + * Testing path translation in combination with multiple psr4_paths + src_directory, no prefixes. + * + * phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] PrefixA=>Some_Other,PrefixB=>PSR4_Path,PrefixC=>MyMy + * phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] PSR4_Path + */ +namespace PrefixB; // OK. + +namespace PrefixA; // Error x 2. +namespace PrefixC; // Error x 2. +namespace PrefixB\PSR4_Path; // Error. +namespace PrefixB\psr4_path; // Error. +namespace PrefixB\PSR4_PATH; // Error. + +/* + * Testing path translation in combination with psr4_paths + src_directory, with prefix, + * when there is no matching PSR4 path due to a case-mismatch. + * + * In that case, the "normal" rules apply. + * + * @phpcs:set Yoast.NamingConventions.NamespaceName prefixes[] Yoast\WP\Plugin + * phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] . + * phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] Prefix\\=>pSr4_path + */ +namespace Yoast\WP\Plugin\PSR4_Path; // OK. +namespace Yoast\WP\Plugin\Psr4_PATH; // OK. +namespace Yoast\WP\Plugin\psr4_path; // OK. + +namespace Prefix; // Error x 2. +namespace Prefix\PSR4_Path; // Error x 2. + +/* + * Testing path translation in combination with psr4_paths + src_directory, with prefix, + * when there is no matching PSR4 path. + * + * In that case, the "normal" rules apply. + * + * @phpcs:set Yoast.NamingConventions.NamespaceName prefixes[] Yoast\WP\Plugin + * phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] . + * phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] PrefixA\\=>not-this-path,PrefixB\\=>Invalid + */ +namespace Yoast\WP\Plugin\PSR4_Path; // OK. +namespace Yoast\WP\Plugin\Psr4_PATH; // OK. +namespace Yoast\WP\Plugin\psr4_path; // OK. + +namespace PrefixA; // Error x 2. +namespace PrefixA\PSR4_Path; // Error x 2. +namespace PrefixB; // Error x 2. +namespace PrefixB\PSR4_Path; // Error x 2. + +// Reset to default settings. +// phpcs:set Yoast.NamingConventions.NamespaceName prefixes[] +// phpcs:set Yoast.NamingConventions.NamespaceName src_directory[] +// phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub path/path-translation-psr4-space.inc b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub path/path-translation-psr4-space.inc new file mode 100644 index 00000000..e85ce7bc --- /dev/null +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub path/path-translation-psr4-space.inc @@ -0,0 +1,12 @@ +PSR4_Path + */ + +namespace Yoast\WP\Plugin\PSR4_Path\Sub Path; // Error: invalid path. Would cause parse error, illegal space in namespace. + +// Reset to default settings. +// phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub#path/path-translation-psr4-hash.inc b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub#path/path-translation-psr4-hash.inc new file mode 100644 index 00000000..ec19dff3 --- /dev/null +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub#path/path-translation-psr4-hash.inc @@ -0,0 +1,12 @@ +PSR4_Path + */ + +namespace Yoast\WP\Plugin\PSR4_Path\Sub#Path; // Error: invalid path. Would cause parse error, unexpected end of file, sniff won't be able to reliably retrieve the namespace. + +// Reset to default settings. +// phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub-path/path-translation-psr4-dash.inc b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub-path/path-translation-psr4-dash.inc new file mode 100644 index 00000000..fe0513e5 --- /dev/null +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub-path/path-translation-psr4-dash.inc @@ -0,0 +1,12 @@ +PSR4_Path + */ + +namespace Yoast\WP\Plugin\PSR4_Path\Sub-Path; // Error: invalid path. Would cause parse error, illegal dash in namespace. + +// Reset to default settings. +// phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub.path/path-translation-psr4-dot.inc b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub.path/path-translation-psr4-dot.inc new file mode 100644 index 00000000..040e4801 --- /dev/null +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/PSR4_Path/sub.path/path-translation-psr4-dot.inc @@ -0,0 +1,12 @@ +PSR4_Path + */ + +namespace Yoast\WP\Plugin\PSR4_Path\Sub.Path; // Error: invalid path. Would cause parse error, illegal concatenation in namespace. + +// Reset to default settings. +// phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] diff --git a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/no-basepath.inc b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/no-basepath.inc index abe5e0df..6da16342 100644 --- a/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/no-basepath.inc +++ b/Yoast/Tests/NamingConventions/NamespaceNameUnitTests/no-basepath.inc @@ -128,8 +128,59 @@ namespace Yoast\WP\Plugin\Tests\Unit\Mocks\Foo\Bar\Baz; // Warning. namespace Yoast\WP\Plugin\Tests\WP\Fixtures\Foo\Bar\Baz; // Warning. namespace Yoast\WP\Plugin\Tests\Unit\Fixtures\Foo\Bar\Baz; // Warning. +/* + * Test allowing for more variations of test directories and deeper double directories based on PSR4 paths. + * + * phpcs:set Yoast.NamingConventions.NamespaceName prefixes[] + * phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] Prefix\Foo=>PSR4_Path,Prefix\Bar=>OtherPath + */ + +namespace Prefix\Foo\Tests\WP\Foo\Bar; // OK. +namespace Prefix\Bar\Tests\Unit\Foo\Bar; // OK. +namespace Prefix\Foo\Tests\WP\Doubles\Foo\Bar; // OK. +namespace Prefix\Bar\Tests\Unit\Doubles\Foo\Bar; // OK. +namespace Prefix\Foo\Tests\WP\Mocks\Foo\Bar; // OK. +namespace Prefix\Bar\Tests\Unit\Mocks\Foo\Bar; // OK. +namespace Prefix\Foo\Tests\WP\Fixtures\Foo\Bar; // OK. +namespace Prefix\Bar\Tests\Unit\Fixtures\Foo\Bar; // OK. + +namespace Prefix\Foo\Tests\WP\Foo\Bar\Baz; // Warning. +namespace Prefix\Bar\Tests\Unit\Foo\Bar\Baz; // Warning. +namespace Prefix\Foo\Tests\WP\Doubles\Foo\Bar\Baz; // Warning. +namespace Prefix\Bar\Tests\Unit\Doubles\Foo\Bar\Baz; // Warning. +namespace Prefix\Foo\Tests\WP\Mocks\Foo\Bar\Baz; // Warning. +namespace Prefix\Bar\Tests\Unit\Mocks\Foo\Bar\Baz; // Warning. +namespace Prefix\Foo\Tests\WP\Fixtures\Foo\Bar\Baz; // Warning. +namespace Prefix\Bar\Tests\Unit\Fixtures\Foo\Bar\Baz; // Warning. + +/* + * Test with PSR4 paths where the prefix already includes `Tests`. + * + * phpcs:set Yoast.NamingConventions.NamespaceName prefixes[] + * phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] PrefixA\Tests\\=>PSR4_Path + */ + +namespace PrefixA\Tests\WP\Foo\Bar; // OK. +namespace PrefixA\Tests\Unit\Foo\Bar; // OK. +namespace PrefixA\Tests\WP\Doubles\Foo\Bar; // OK. +namespace PrefixA\Tests\Unit\Doubles\Foo\Bar; // OK. +namespace PrefixA\Tests\WP\Mocks\Foo\Bar; // OK. +namespace PrefixA\Tests\Unit\Mocks\Foo\Bar; // OK. +namespace PrefixA\Tests\WP\Fixtures\Foo\Bar; // OK. +namespace PrefixA\Tests\Unit\Fixtures\Foo\Bar; // OK. + +namespace PrefixA\Tests\WP\Foo\Bar\Baz; // Warning. +namespace PrefixA\Tests\Unit\Foo\Bar\Baz; // Warning. +namespace PrefixA\Tests\WP\Doubles\Foo\Bar\Baz; // Warning. +namespace PrefixA\Tests\Unit\Doubles\Foo\Bar\Baz; // Warning. +namespace PrefixA\Tests\WP\Mocks\Foo\Bar\Baz; // Warning. +namespace PrefixA\Tests\Unit\Mocks\Foo\Bar\Baz; // Warning. +namespace PrefixA\Tests\WP\Fixtures\Foo\Bar\Baz; // Warning. +namespace PrefixA\Tests\Unit\Fixtures\Foo\Bar\Baz; // Warning. + // Reset to default settings. // phpcs:set Yoast.NamingConventions.NamespaceName prefixes[] +// phpcs:set Yoast.NamingConventions.NamespaceName psr4_paths[] /* * Test against false positives for namespace operator and incorrect namespace declarations.