diff --git a/CHANGES.md b/CHANGES.md index ed9f2399..646acff9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,7 @@ +Changes in version 5.0.10 (20250730) - Too soon? +------------------------------------------------------- +- Fixed bundled dependencies + Changes in version 5.0.9 (20250730) - Long time no bump ------------------------------------------------------- - Bundled dependencies updated: diff --git a/vendor/autoload.php b/vendor/autoload.php index c27f5fcd..e6b418ae 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -22,4 +22,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInitf911c1a21380142d6ee33490dc0eee6a::getLoader(); +return ComposerAutoloaderInit574d662ebe51df2403d0358535dbfb75::getLoader(); diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php index 07b32ed6..6d29bff6 100644 --- a/vendor/composer/InstalledVersions.php +++ b/vendor/composer/InstalledVersions.php @@ -32,6 +32,11 @@ class InstalledVersions */ private static $installed; + /** + * @var bool + */ + private static $installedIsLocalDir; + /** * @var bool|null */ @@ -309,6 +314,12 @@ public static function reload($data) { self::$installed = $data; self::$installedByVendor = array(); + + // when using reload, we disable the duplicate protection to ensure that self::$installed data is + // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, + // so we have to assume it does not, and that may result in duplicate data being returned when listing + // all installed packages for example + self::$installedIsLocalDir = false; } /** @@ -325,7 +336,9 @@ private static function getInstalled() $copiedLocalDir = false; if (self::$canGetVendors) { + $selfDir = strtr(__DIR__, '\\', '/'); foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + $vendorDir = strtr($vendorDir, '\\', '/'); if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { @@ -333,11 +346,14 @@ private static function getInstalled() $required = require $vendorDir.'/composer/installed.php'; self::$installedByVendor[$vendorDir] = $required; $installed[] = $required; - if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { self::$installed = $required; - $copiedLocalDir = true; + self::$installedIsLocalDir = true; } } + if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { + $copiedLocalDir = true; + } } } diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 1e61f460..f8c7fbb9 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInitf911c1a21380142d6ee33490dc0eee6a +class ComposerAutoloaderInit574d662ebe51df2403d0358535dbfb75 { private static $loader; @@ -24,12 +24,12 @@ public static function getLoader() require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInitf911c1a21380142d6ee33490dc0eee6a', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit574d662ebe51df2403d0358535dbfb75', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInitf911c1a21380142d6ee33490dc0eee6a', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit574d662ebe51df2403d0358535dbfb75', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInitf911c1a21380142d6ee33490dc0eee6a::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit574d662ebe51df2403d0358535dbfb75::getInitializer($loader)); $loader->register(true); diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index b970dbc3..c3870794 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInitf911c1a21380142d6ee33490dc0eee6a +class ComposerStaticInit574d662ebe51df2403d0358535dbfb75 { public static $prefixLengthsPsr4 = array ( 'P' => @@ -85,9 +85,9 @@ class ComposerStaticInitf911c1a21380142d6ee33490dc0eee6a public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInitf911c1a21380142d6ee33490dc0eee6a::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInitf911c1a21380142d6ee33490dc0eee6a::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInitf911c1a21380142d6ee33490dc0eee6a::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit574d662ebe51df2403d0358535dbfb75::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit574d662ebe51df2403d0358535dbfb75::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit574d662ebe51df2403d0358535dbfb75::$classMap; }, null, ClassLoader::class); } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 84c82b01..11a35423 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -189,15 +189,15 @@ }, "require": { "php": ">=5.4", - "phpcsstandards/phpcsutils": "^1.0.12", - "squizlabs/php_codesniffer": "^3.10.0" + "phpcsstandards/phpcsutils": "^1.1.0", + "squizlabs/php_codesniffer": "^3.13.0" }, "replace": { "wimg/php-compatibility": "*" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0.0", - "php-parallel-lint/php-parallel-lint": "^1.3.2", + "php-parallel-lint/php-parallel-lint": "^1.4.0", "phpcsstandards/phpcsdevcs": "^1.1.3", "phpcsstandards/phpcsdevtools": "^1.2.0", "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4 || ^10.1.0", @@ -206,7 +206,7 @@ "suggest": { "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." }, - "time": "2024-06-07T09:46:11+00:00", + "time": "2025-07-06T15:59:37+00:00", "default-branch": true, "type": "phpcodesniffer-standard", "extra": { @@ -237,7 +237,7 @@ } ], "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", - "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", + "homepage": "https://techblog.wimgodden.be/tag/codesniffer/", "keywords": [ "compatibility", "phpcs", @@ -261,6 +261,10 @@ { "url": "https://opencollective.com/php_codesniffer", "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcompatibility", + "type": "thanks_dev" } ], "install-path": "../phpcompatibility/php-compatibility" diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 726cfed9..ba809a67 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'moodlehq/local_codechecker', 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => 'b4422b004fe63360eaa73113e537604bd2efd2d6', + 'reference' => '38602b55f5fb5b0c05b34de293c0e475e357e93b', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -22,7 +22,7 @@ 'moodlehq/local_codechecker' => array( 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => 'b4422b004fe63360eaa73113e537604bd2efd2d6', + 'reference' => '38602b55f5fb5b0c05b34de293c0e475e357e93b', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), diff --git a/vendor/dealerdirect/phpcodesniffer-composer-installer/CHANGELOG.md b/vendor/dealerdirect/phpcodesniffer-composer-installer/CHANGELOG.md new file mode 100644 index 00000000..3a55c0d2 --- /dev/null +++ b/vendor/dealerdirect/phpcodesniffer-composer-installer/CHANGELOG.md @@ -0,0 +1,575 @@ +# Change Log for the Composer Installer for PHP CodeSniffer + +All notable changes to this project will be documented in this file. + +This projects adheres to [Keep a CHANGELOG](https://keepachangelog.com/) and uses [Semantic Versioning](https://semver.org/). + + +## [Unreleased] + +_Nothing yet._ + + +## [v1.1.2] - 2025-07-17 + +### Changed +- General housekeeping. + +### Fixed +- [#247]: Potential fatal error when the Composer EventDispatcher is called programmatically from an integration. Thanks [@jrfnl] ! [#248] + +[#247]: https://github.com/PHPCSStandards/composer-installer/issues/247 +[#248]: https://github.com/PHPCSStandards/composer-installer/pull/248 + + +## [v1.1.1] - 2025-06-27 + +### Changed +- Various housekeeping, including improvements to the documentation. + +### Fixed +- [#239]: The PHP_CodeSniffer package could not be always found when running the plugin in a Drupal or Magento setup. Thanks [@jrfnl] ! [#245] + +[#239]: https://github.com/PHPCSStandards/composer-installer/issues/239 +[#245]: https://github.com/PHPCSStandards/composer-installer/pull/245 + + +## [v1.1.0] - 2025-06-24 + +### Changed +- Various housekeeping, including improvements to the documentation and tests. Thanks [@SplotyCode], [@fredden] for contributing! + +### Removed +- Drop support for Composer v1.x. Thanks [@fredden] ! [#230] + +[#230]: https://github.com/PHPCSStandards/composer-installer/pull/230 + + +## [v1.0.0] - 2023-01-05 + +### Breaking changes +- Rename namespace prefix from Dealerdirect to PHPCSStandards by [@jrfnl] in [#191] +- Drop support for PHP 5.3 by [@jrfnl] in [#147] + +### Changed +- Correct grammar in error message by [@fredden] in [#189] +- .gitattributes: sync with current repo state by [@jrfnl] in [#198] +- PHPCSVersions: update URL references by [@jrfnl] in [#161] +- README: remove references to Scrutinizer by [@jrfnl] in [#157] +- Rename references to master branch by [@Potherca] in [#201] +- Update repo references by [@jrfnl] in [#158] +- GH Actions: add builds against Composer 2.2 for PHP 7.2 - 8.x by [@jrfnl] in [#172] +- GH Actions: bust the cache semi-regularly by [@jrfnl] in [#192] +- GH Actions: fix builds on Windows with PHP 8.2 by [@jrfnl] in [#180] +- GH Actions: fix up fail-fast for setup-php by [@jrfnl] in [#195] +- GH Actions: run integration tests against Composer snapshot by [@jrfnl] in [#163] +- GH Actions: run linting against against ubuntu-latest by [@jrfnl] in [#184] +- GH Actions/Securitycheck: update the security checker download by [@jrfnl] in [#178] +- GH Actions/Securitycheck: update the security checker download by [@jrfnl] in [#186] +- GH Actions/Securitycheck: update the security checker download by [@jrfnl] in [#190] +- GH Actions: selectively use fail-fast with setup-php by [@jrfnl] in [#194] +- GH Actions: stop running tests against PHP 5.5/Composer 1.x on Windows (and remove work-arounds) by [@jrfnl] in [#183] +- GH Actions: various tweaks / PHP 8.2 not allowed to fail by [@jrfnl] in [#193] +- GH Actions: version update for various predefined actions by [@jrfnl] in [#170] +- Update YamLint by [@Potherca] in [#173] +- Add initial integration test setup and first few tests by [@jrfnl] in [#153] +- BaseLineTest: stabilize the message checks by [@jrfnl] in [#162] +- PlayNiceWithScriptsTest: wrap output expectation in condition by [@jrfnl] in [#179] +- RegisterExternalStandardsTest: add new tests by [@jrfnl] in [#165] +- RegisterExternalStandardsTest: stabilize test for Composer v1 on Windows with PHP 5.5 by [@jrfnl] in [#171] +- TestCase::executeCliCommand(): retry Composer commands on a particular exception by [@jrfnl] in [#164] +- Tests: add new InstalledPathsOrderTest by [@jrfnl] in [#176] +- Tests: add new InstallUpdateEventsTest and NonInstallUpdateEventsTest by [@jrfnl] in [#174] +- Tests: add new InvalidPackagesTest by [@jrfnl] in [#168] +- Tests: add new PlayNiceWithScriptsTest by [@jrfnl] in [#169] +- Tests: add new PreexistingPHPCSConfigTest by [@jrfnl] in [#166] +- Tests: add new PreexistingPHPCSInstalledPathsConfigTest + bug fix by [@jrfnl] in [#167] +- Tests: add new RemovePluginTest by [@jrfnl] in [#177] +- Tests: add new RootPackageHandlingTest + bugfix by [@jrfnl] in [#175] + +### Fixed +- Plugin: improve feedback by [@jrfnl] in [#182] + +[#147]: https://github.com/PHPCSStandards/composer-installer/pull/147 +[#153]: https://github.com/PHPCSStandards/composer-installer/pull/153 +[#157]: https://github.com/PHPCSStandards/composer-installer/pull/157 +[#158]: https://github.com/PHPCSStandards/composer-installer/pull/158 +[#161]: https://github.com/PHPCSStandards/composer-installer/pull/161 +[#162]: https://github.com/PHPCSStandards/composer-installer/pull/162 +[#163]: https://github.com/PHPCSStandards/composer-installer/pull/163 +[#164]: https://github.com/PHPCSStandards/composer-installer/pull/164 +[#165]: https://github.com/PHPCSStandards/composer-installer/pull/165 +[#166]: https://github.com/PHPCSStandards/composer-installer/pull/166 +[#167]: https://github.com/PHPCSStandards/composer-installer/pull/167 +[#168]: https://github.com/PHPCSStandards/composer-installer/pull/168 +[#169]: https://github.com/PHPCSStandards/composer-installer/pull/169 +[#170]: https://github.com/PHPCSStandards/composer-installer/pull/170 +[#171]: https://github.com/PHPCSStandards/composer-installer/pull/171 +[#172]: https://github.com/PHPCSStandards/composer-installer/pull/172 +[#173]: https://github.com/PHPCSStandards/composer-installer/pull/173 +[#174]: https://github.com/PHPCSStandards/composer-installer/pull/174 +[#175]: https://github.com/PHPCSStandards/composer-installer/pull/175 +[#176]: https://github.com/PHPCSStandards/composer-installer/pull/176 +[#177]: https://github.com/PHPCSStandards/composer-installer/pull/177 +[#178]: https://github.com/PHPCSStandards/composer-installer/pull/178 +[#179]: https://github.com/PHPCSStandards/composer-installer/pull/179 +[#180]: https://github.com/PHPCSStandards/composer-installer/pull/180 +[#182]: https://github.com/PHPCSStandards/composer-installer/pull/182 +[#183]: https://github.com/PHPCSStandards/composer-installer/pull/183 +[#184]: https://github.com/PHPCSStandards/composer-installer/pull/184 +[#186]: https://github.com/PHPCSStandards/composer-installer/pull/186 +[#189]: https://github.com/PHPCSStandards/composer-installer/pull/189 +[#190]: https://github.com/PHPCSStandards/composer-installer/pull/190 +[#191]: https://github.com/PHPCSStandards/composer-installer/pull/191 +[#192]: https://github.com/PHPCSStandards/composer-installer/pull/192 +[#193]: https://github.com/PHPCSStandards/composer-installer/pull/193 +[#194]: https://github.com/PHPCSStandards/composer-installer/pull/194 +[#195]: https://github.com/PHPCSStandards/composer-installer/pull/195 +[#198]: https://github.com/PHPCSStandards/composer-installer/pull/198 +[#201]: https://github.com/PHPCSStandards/composer-installer/pull/201 + + +## [v0.7.2] - 2022-02-04 + +### Changed +- Add details regarding QA automation in CONTRIBUTING.md file. by [@Potherca] in [#133] +- Add mention of Composer and PHP compatibility to project README. by [@Potherca] in [#132] +- Composer: tweak PHPCS version constraint by [@jrfnl] in [#152] +- CONTRIBUTING: remove duplicate code of conduct by [@jrfnl] in [#148] +- Document release process by [@Potherca] in [#118] +- Plugin::loadInstalledPaths(): config-show always shows all by [@jrfnl] in [#154] +- README: minor tweaks by [@jrfnl] in [#149] +- README: update with information about Composer >= 2.2 by [@jrfnl] in [#141] +- Replace deprecated Sensiolabs security checker by [@paras-malhotra] in [#130] +- Stabilize a condition by [@jrfnl] in [#127] +- Update copyright year by [@jrfnl] in [#138] +- Various minor tweaks by [@jrfnl] in [#151] +- Change YamlLint config to prevent "truthy" warning. by [@Potherca] in [#144] +- GH Actions: PHP 8.1 has been released by [@jrfnl] in [#139] +- Travis: line length tweaks by [@jrfnl] in [#128] +- CI: Switch to GH Actions by [@jrfnl] in [#137] +- CI: various updates by [@jrfnl] in [#140] + +[#118]: https://github.com/PHPCSStandards/composer-installer/pull/118 +[#127]: https://github.com/PHPCSStandards/composer-installer/pull/127 +[#128]: https://github.com/PHPCSStandards/composer-installer/pull/128 +[#130]: https://github.com/PHPCSStandards/composer-installer/pull/130 +[#132]: https://github.com/PHPCSStandards/composer-installer/pull/132 +[#133]: https://github.com/PHPCSStandards/composer-installer/pull/133 +[#137]: https://github.com/PHPCSStandards/composer-installer/pull/137 +[#138]: https://github.com/PHPCSStandards/composer-installer/pull/138 +[#139]: https://github.com/PHPCSStandards/composer-installer/pull/139 +[#140]: https://github.com/PHPCSStandards/composer-installer/pull/140 +[#141]: https://github.com/PHPCSStandards/composer-installer/pull/141 +[#144]: https://github.com/PHPCSStandards/composer-installer/pull/144 +[#148]: https://github.com/PHPCSStandards/composer-installer/pull/148 +[#149]: https://github.com/PHPCSStandards/composer-installer/pull/149 +[#151]: https://github.com/PHPCSStandards/composer-installer/pull/151 +[#152]: https://github.com/PHPCSStandards/composer-installer/pull/152 +[#154]: https://github.com/PHPCSStandards/composer-installer/pull/154 + + +## [v0.7.1] - 2020-12-07 + +### Closed issues +- Order of installed_paths inconsistent between runs [#125] +- Maintaining this project and Admin rights [#113] + +### Changed +- Sort list of installed paths before saving for consistency by [@kevinfodness] in [#126] +- Update code of conduct by [@Potherca] in [#117] +- Add remark configuration by [@Potherca] in [#122] +- Travis: add build against PHP 8.0 by [@jrfnl] in [#124] + +### Fixed +- Fixed v4 constraint by [@GrahamCampbell] in [#115] + +[#113]: https://github.com/PHPCSStandards/composer-installer/issues/113 +[#115]: https://github.com/PHPCSStandards/composer-installer/pull/115 +[#117]: https://github.com/PHPCSStandards/composer-installer/pull/117 +[#122]: https://github.com/PHPCSStandards/composer-installer/pull/122 +[#124]: https://github.com/PHPCSStandards/composer-installer/pull/124 +[#125]: https://github.com/PHPCSStandards/composer-installer/issues/125 +[#126]: https://github.com/PHPCSStandards/composer-installer/pull/126 + + +## [v0.7.0] - 2020-06-25 + +### Closed issues +- Composer 2.x compatibility [#108] +- Add link to Packagist on main page [#110] +- Switch from Travis CI .org to .com [#112] + +### Added +- Allow installation on PHP 8 by [@jrfnl] in [#106] +- Support Composer 2.0 by [@jrfnl] in [#111] + +### Changed +- Test with PHPCS 4.x and allow installation when using PHPCS 4.x by [@jrfnl] in [#107] +- Fix case of class name by [@Seldaek] in [#109] + +[#106]: https://github.com/PHPCSStandards/composer-installer/pull/106 +[#107]: https://github.com/PHPCSStandards/composer-installer/pull/107 +[#108]: https://github.com/PHPCSStandards/composer-installer/issues/108 +[#109]: https://github.com/PHPCSStandards/composer-installer/pull/109 +[#110]: https://github.com/PHPCSStandards/composer-installer/issues/110 +[#111]: https://github.com/PHPCSStandards/composer-installer/pull/111 +[#112]: https://github.com/PHPCSStandards/composer-installer/issues/112 + + +## [v0.6.2] - 2020-01-29 + +### Fixed +- Composer scripts/commands broken in 0.6.0 update by [@BrianHenryIE] in [#105] + +[#105]: https://github.com/PHPCSStandards/composer-installer/pull/105 + +## [v0.6.1] - 2020-01-27 + +### Closed issues +- Do not exit with code 1 on uninstall (--no-dev) [#103] + +### Changed +- Readme: minor tweak now 0.6.0 has been released [#102] ([@jrfnl]) + +### Fixed +- [#103]: Fix for issue #103 [#104] ([@Potherca]) + +[#102]: https://github.com/PHPCSStandards/composer-installer/pull/102 +[#103]: https://github.com/PHPCSStandards/composer-installer/issues/103 +[#104]: https://github.com/PHPCSStandards/composer-installer/pull/104 + + +## [v0.6.0] - 2020-01-19 + +### Closed issues +- Composer PHP version appears not to be respected [#79] +- Allow a string value for extra.phpcodesniffer-search-depth [#82] +- Add [@jrfnl] as (co)maintainer to this project [#87] + +### Added +- Add support for a string phpcodesniffer-search-depth config value set via composer config by [@TravisCarden] in [#85] +- Send an exit code when the script terminates by [@jrfnl] in [#93] +- Verify the installed_paths after save by [@jrfnl] in [#97] + +### Changed +- CS: fix compliance with PSR12 by [@jrfnl] in [#88] +- Improve GH issue template by [@jrfnl] in [#94] +- Readme: add section about including this plugin from an external PHPCS standard by [@jrfnl] in [#95] +- Bug report template: further enhancement by [@jrfnl] in [#99] +- Update copyright year. by [@Potherca] in [#101] +- Adding linting jobs in github action by [@mjrider] in [#96] +- GH Actions: minor tweaks: by [@jrfnl] in [#100] +- Travis: disable Xdebug by [@jrfnl] in [#89] +- Travis: test against PHP 7.4, not snapshot by [@jrfnl] in [#90] +- Travis: use a mix of PHPCS versions in the matrix by [@jrfnl] in [#91] +- Update Travis file and fix build by [@Potherca] in [#86] + +### Fixed +- [#79]: Respect PHP version used by Composer and provide better feedback on failure by [@jrfnl] in [#80] +- Bug fix: loadInstalledPaths() very very broken since PHPCS 3.1.0 by [@jrfnl] in [#98] + +[#79]: https://github.com/PHPCSStandards/composer-installer/issues/79 +[#80]: https://github.com/PHPCSStandards/composer-installer/issues/80 +[#82]: https://github.com/PHPCSStandards/composer-installer/issues/82 +[#85]: https://github.com/PHPCSStandards/composer-installer/pull/85 +[#86]: https://github.com/PHPCSStandards/composer-installer/pull/86 +[#87]: https://github.com/PHPCSStandards/composer-installer/issues/87 +[#88]: https://github.com/PHPCSStandards/composer-installer/pull/88 +[#89]: https://github.com/PHPCSStandards/composer-installer/pull/89 +[#90]: https://github.com/PHPCSStandards/composer-installer/pull/90 +[#91]: https://github.com/PHPCSStandards/composer-installer/pull/91 +[#93]: https://github.com/PHPCSStandards/composer-installer/pull/93 +[#94]: https://github.com/PHPCSStandards/composer-installer/pull/94 +[#95]: https://github.com/PHPCSStandards/composer-installer/pull/95 +[#96]: https://github.com/PHPCSStandards/composer-installer/pull/96 +[#97]: https://github.com/PHPCSStandards/composer-installer/pull/97 +[#98]: https://github.com/PHPCSStandards/composer-installer/issues/98 +[#99]: https://github.com/PHPCSStandards/composer-installer/pull/99 +[#100]: https://github.com/PHPCSStandards/composer-installer/pull/100 +[#101]: https://github.com/PHPCSStandards/composer-installer/pull/101 + + +## [v0.5.0] - 2018-10-26 + +### Closed issues +- Scan depth as parameter [#45] +- phpcs: Exit Code: 127 (Command not found) on every Composer command [#48] +- The composer plugin implementation seems to be breaking the composer lifecycle [#49] +- Installation error [#53] +- Broke composer commands when used with wp-cli/package-command [#59] +- Getting a new stable release [#60] +- Support PHP CodeSniffer standards in packages installed outside of the vendor directory [#63] + +### Added +- Adds the ability to set the max depth from the composer.json file by [@Potherca] in [#46] + +### Changed +- Build/PHPCS: update PHPCompatibility repo name by [@jrfnl] in [#54] +- README: remove VersionEye badge by [@jrfnl] in [#55] +- README: replace maintenance badge by [@jrfnl] in [#56] +- Execute phpcs and security-checker from vendor/bin by [@gapple] in [#52] +- PHPCS: various minor tweaks by [@jrfnl] in [#57] +- Travis: various tweaks by [@jrfnl] in [#58] +- Use PHPCompatibility 9.0.0 by [@jrfnl] in [#61] +- Build/Travis: test builds against PHP 7.3 by [@jrfnl] in [#62] +- Updates copyright year by [@frenck] in [#67] +- Enforces PSR12 by [@frenck] in [#66] +- Updates contact information by [@frenck] in [#68] +- Updates README, spelling/grammar, removed Working section by [@frenck] in [#69] +- Replaces ProcessBuilder by ProcessExecutor by [@frenck] in [#70] +- Refactors relative path logic by [@frenck] in [#71] +- Removes suggested packages by [@frenck] in [#72] +- Ensures absolute paths during detection phase by [@frenck] in [#73] +- Trivial code cleanup by [@frenck] in [#74] +- Fixes duplicate declaration of cwd by [@frenck] in [#75] +- Removes HHVM from TravisCI by [@frenck] in [#76] +- Adds PHP_CodeSniffer version constraints by [@frenck] in [#77] + +### Fixed +- [#49]: Move loadInstalledPaths from init to onDependenciesChangedEvent by [@gapple] in [#51] + +[#45]: https://github.com/PHPCSStandards/composer-installer/issues/45 +[#46]: https://github.com/PHPCSStandards/composer-installer/pull/46 +[#48]: https://github.com/PHPCSStandards/composer-installer/issues/48 +[#49]: https://github.com/PHPCSStandards/composer-installer/issues/49 +[#51]: https://github.com/PHPCSStandards/composer-installer/pull/51 +[#52]: https://github.com/PHPCSStandards/composer-installer/pull/52 +[#53]: https://github.com/PHPCSStandards/composer-installer/issues/53 +[#54]: https://github.com/PHPCSStandards/composer-installer/pull/54 +[#55]: https://github.com/PHPCSStandards/composer-installer/pull/55 +[#56]: https://github.com/PHPCSStandards/composer-installer/pull/56 +[#57]: https://github.com/PHPCSStandards/composer-installer/pull/57 +[#58]: https://github.com/PHPCSStandards/composer-installer/pull/58 +[#59]: https://github.com/PHPCSStandards/composer-installer/issues/59 +[#60]: https://github.com/PHPCSStandards/composer-installer/issues/60 +[#61]: https://github.com/PHPCSStandards/composer-installer/pull/61 +[#62]: https://github.com/PHPCSStandards/composer-installer/pull/62 +[#63]: https://github.com/PHPCSStandards/composer-installer/issues/63 +[#66]: https://github.com/PHPCSStandards/composer-installer/pull/66 +[#67]: https://github.com/PHPCSStandards/composer-installer/pull/67 +[#68]: https://github.com/PHPCSStandards/composer-installer/pull/68 +[#69]: https://github.com/PHPCSStandards/composer-installer/pull/69 +[#70]: https://github.com/PHPCSStandards/composer-installer/pull/70 +[#71]: https://github.com/PHPCSStandards/composer-installer/pull/71 +[#72]: https://github.com/PHPCSStandards/composer-installer/pull/72 +[#73]: https://github.com/PHPCSStandards/composer-installer/pull/73 +[#74]: https://github.com/PHPCSStandards/composer-installer/pull/74 +[#75]: https://github.com/PHPCSStandards/composer-installer/pull/75 +[#76]: https://github.com/PHPCSStandards/composer-installer/pull/76 +[#77]: https://github.com/PHPCSStandards/composer-installer/pull/77 + + +## [v0.4.4] - 2017-12-06 + +### Closed issues +- PHP 7.2 compatibility issue [#43] + +### Changed +- Update Travis CI svg badge and link URLs [#42] ([@ntwb]) +- Add PHP 7.2 to Travis CI [#41] ([@ntwb]) +- Docs: Fix link to releases [#40] ([@GaryJones]) + +[#40]: https://github.com/PHPCSStandards/composer-installer/pull/40 +[#41]: https://github.com/PHPCSStandards/composer-installer/pull/41 +[#42]: https://github.com/PHPCSStandards/composer-installer/pull/42 +[#43]: https://github.com/PHPCSStandards/composer-installer/issues/43 + + +## [v0.4.3] - 2017-09-18 + +### Changed +- CS: Add PHP 5.3 compatibility [#39] ([@GaryJones]) +- Local PHPCS [#38] ([@GaryJones]) + +[#38]: https://github.com/PHPCSStandards/composer-installer/pull/38 +[#39]: https://github.com/PHPCSStandards/composer-installer/pull/39 + + +## [v0.4.2] - 2017-08-16 + +### Changed +- Docs: Rename example script [#35] ([@GaryJones]) +- Update README.md [#36] ([@jrfnl]) +- Documentation update. [#37] ([@frenck]) + +[#35]: https://github.com/PHPCSStandards/composer-installer/pull/35 +[#36]: https://github.com/PHPCSStandards/composer-installer/pull/36 +[#37]: https://github.com/PHPCSStandards/composer-installer/pull/37 + + +## [v0.4.1] - 2017-08-01 + +### Closed issues +- Incorrect relative paths for WPCS [#33] + +### Fixed +- [#33]: Changes the way the installed_paths are set. [#34] ([@frenck]) + +[#33]: https://github.com/PHPCSStandards/composer-installer/issues/33 +[#34]: https://github.com/PHPCSStandards/composer-installer/pull/34 + + +## [v0.4.0] - 2017-05-11 + +### Closed issues +- Add support for code standards in root of repository for PHP_CodeSniffer 3.x [#26] +- Config codings styles in composer.json from project [#23] +- Check the root package for sniffs to install [#20] +- Document the ability to execute the main plugin functionality directly [#18] +- Add a CHANGELOG.md [#17] +- Install sniffs with relative paths in CodeSniffer.conf [#14] + +### Added +- Support for coding standard in the root repository for PHP_CodeSniffer v3.x [#30] ([@frenck]) +- Added support for having coding standards in the root package [#25] ([@frenck]) + +### Changed +- Local projects uses relative paths to their coding standards [#28] ([@frenck]) +- Docs: Updated README. [#31] ([@frenck]) +- Docs: Adds reference to calling the script directly in the README. [#29] ([@Potherca]) +- Adds Travis-CI configuration file. [#27] ([@Potherca]) + + +[#14]: https://github.com/PHPCSStandards/composer-installer/issues/14 +[#17]: https://github.com/PHPCSStandards/composer-installer/issues/17 +[#18]: https://github.com/PHPCSStandards/composer-installer/issues/18 +[#20]: https://github.com/PHPCSStandards/composer-installer/issues/20 +[#23]: https://github.com/PHPCSStandards/composer-installer/issues/23 +[#25]: https://github.com/PHPCSStandards/composer-installer/pull/25 +[#26]: https://github.com/PHPCSStandards/composer-installer/issues/26 +[#27]: https://github.com/PHPCSStandards/composer-installer/pull/27 +[#28]: https://github.com/PHPCSStandards/composer-installer/pull/28 +[#29]: https://github.com/PHPCSStandards/composer-installer/pull/29 +[#31]: https://github.com/PHPCSStandards/composer-installer/pull/31 + + +## [v0.3.2] - 2017-03-29 + +### Closed issues +- Coding Standard tries itself to install with installPath when it's the root package [#19] + +### Changed +- Improvements to the documentation [#22] ([@Potherca]) +- Added instanceof check to prevent root package from being installed [#21] ([@bastianschwarz]) + +### Fixed +- [#13]: Incorrect coding standards search depth [#15] ([@frenck]) + +[#19]: https://github.com/PHPCSStandards/composer-installer/issues/19 +[#21]: https://github.com/PHPCSStandards/composer-installer/pull/21 +[#22]: https://github.com/PHPCSStandards/composer-installer/pull/22 + + +## [v0.3.1] - 2017-02-17 + +### Closed issues +- Plugin not working correctly when sniffs install depth is equal to "1" [#13] +- Create new stable release version to support wider use [#11] + +### Fixed +- [#13]: Incorrect coding standards search depth [#15] ([@frenck]) + +[#11]: https://github.com/PHPCSStandards/composer-installer/issues/11 +[#13]: https://github.com/PHPCSStandards/composer-installer/issues/13 +[#15]: https://github.com/PHPCSStandards/composer-installer/pull/15 + + +## [v0.3.0] - 2017-02-15 + +### Implemented enhancements +- Install Plugin provides no feedback [#7] +- Installing coding standards when executing Composer with --no-scripts [#4] +- Github contribution templates [#10] ([@christopher-hopper]) +- Show config actions and a result as Console output [#8] ([@christopher-hopper]) +- Adds static function to call the Plugin::onDependenciesChangedEvent() method [#5] ([@Potherca]) + +### Added +- Support existing standards packages with subfolders [#6] ([@christopher-hopper]) + +### Changed +- Improved documentation [#12] ([@frenck]) +- Removal of lgtm.co [#3] ([@frenck]) + +[#3]: https://github.com/PHPCSStandards/composer-installer/pull/3 +[#4]: https://github.com/PHPCSStandards/composer-installer/issues/4 +[#5]: https://github.com/PHPCSStandards/composer-installer/pull/5 +[#6]: https://github.com/PHPCSStandards/composer-installer/pull/6 +[#7]: https://github.com/PHPCSStandards/composer-installer/issues/7 +[#8]: https://github.com/PHPCSStandards/composer-installer/pull/8 +[#10]: https://github.com/PHPCSStandards/composer-installer/pull/10 +[#12]: https://github.com/PHPCSStandards/composer-installer/pull/12 + + +## [v0.2.1] - 2016-11-01 + +Fixes an issue with having this plugin installed globally within composer, but using your global composer installation on a local repository without PHP_CodeSniffer installed. + +### Fixed +- Bugfix: Plugin fails when PHP_CodeSniffer is not installed [#2] ([@frenck]) + +[#2]: https://github.com/PHPCSStandards/composer-installer/pull/2 + + +## [v0.2.0] - 2016-11-01 + +For this version on, this installer no longer messes with the installation paths of composer libraries, but instead, it configures PHP_CodeSniffer to look into other directories for coding standards. + +### Changed +- PHPCS Configuration management [#1] ([@frenck]) + +[#1]: https://github.com/PHPCSStandards/composer-installer/pull/1 + + +## [v0.1.1] - 2016-10-24 + +### Changed +- Standard name mapping improvements + + +## v0.1.0 - 2016-10-23 + +First useable release. + +[v1.1.2]: https://github.com/PHPCSStandards/composer-installer/compare/v1.1.1...v1.1.2 +[v1.1.1]: https://github.com/PHPCSStandards/composer-installer/compare/v1.1.0...v1.1.1 +[v1.1.0]: https://github.com/PHPCSStandards/composer-installer/compare/v1.0.0...v1.1.0 +[v1.0.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.7.2...v1.0.0 +[v0.7.2]: https://github.com/PHPCSStandards/composer-installer/compare/v0.7.1...v0.7.2 +[v0.7.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.7.0...v0.7.1 +[v0.7.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.6.2...v0.7.0 +[v0.6.2]: https://github.com/PHPCSStandards/composer-installer/compare/v0.6.1...v0.6.2 +[v0.6.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.6.0...v0.6.1 +[v0.6.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.5.0...v0.6.0 +[v0.5.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.4...v0.5.0 +[v0.4.4]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.3...v0.4.4 +[v0.4.3]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.2...v0.4.3 +[v0.4.2]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.1...v0.4.2 +[v0.4.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.0...v0.4.1 +[v0.4.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.3.2...v0.4.0 +[v0.3.2]: https://github.com/PHPCSStandards/composer-installer/compare/v0.3.1...v0.3.2 +[v0.3.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.3.0...v0.3.1 +[v0.3.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.2.1...v0.3.0 +[v0.2.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.1.1...v0.2.0 +[v0.1.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.1.0...v0.1.1 + +[PHP_CodeSniffer]: https://github.com/PHPCSStandards/PHP_CodeSniffer + +[@bastianschwarz]: https://github.com/bastianschwarz +[@BrianHenryIE]: https://github.com/BrianHenryIE +[@christopher-hopper]: https://github.com/christopher-hopper +[@fredden]: https://github.com/fredden +[@frenck]: https://github.com/frenck +[@gapple]: https://github.com/gapple +[@GaryJones]: https://github.com/GaryJones +[@GrahamCampbell]: https://github.com/GrahamCampbell +[@jrfnl]: https://github.com/jrfnl +[@kevinfodness]: https://github.com/kevinfodness +[@mjrider]: https://github.com/mjrider +[@ntwb]: https://github.com/ntwb +[@paras-malhotra]: https://github.com/paras-malhotra +[@Potherca]: https://github.com/Potherca +[@Seldaek]: https://github.com/Seldaek +[@SplotyCode]: https://github.com/SplotyCode +[@TravisCarden]: https://github.com/TravisCarden diff --git a/vendor/phpcsstandards/phpcsextra/Universal/Docs/PHP/NoFQNTrueFalseNullStandard.xml b/vendor/phpcsstandards/phpcsextra/Universal/Docs/PHP/NoFQNTrueFalseNullStandard.xml new file mode 100644 index 00000000..205b4661 --- /dev/null +++ b/vendor/phpcsstandards/phpcsextra/Universal/Docs/PHP/NoFQNTrueFalseNullStandard.xml @@ -0,0 +1,27 @@ + + + + + + + + null; + +if ($something === false) {} + ]]> + + + \null; + +if ($something === \false) {} + ]]> + + + diff --git a/vendor/phpcsstandards/phpcsextra/Universal/Sniffs/PHP/NoFQNTrueFalseNullSniff.php b/vendor/phpcsstandards/phpcsextra/Universal/Sniffs/PHP/NoFQNTrueFalseNullSniff.php new file mode 100644 index 00000000..e9354b8d --- /dev/null +++ b/vendor/phpcsstandards/phpcsextra/Universal/Sniffs/PHP/NoFQNTrueFalseNullSniff.php @@ -0,0 +1,109 @@ + + */ + public function register() + { + return [ + // PHPCS 3.x on PHP < 8.0. + \T_TRUE, + \T_FALSE, + \T_NULL, + + // PHPCS 3.x on PHP >= 8.0. + \T_STRING, + + // PHPCS 4.x. + \T_NAME_FULLY_QUALIFIED, + ]; + } + + /** + * Processes this test, when one of its tokens is encountered. + * + * @since 1.3.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $content = $tokens[$stackPtr]['content']; + $contentLC = \strtolower($content); + + if ($tokens[$stackPtr]['code'] === \T_NAME_FULLY_QUALIFIED) { + // PHPCS 4.x. + if ($contentLC !== '\true' && $contentLC !== '\false' && $contentLC !== '\null') { + return; + } + } else { + // PHPCS 3.x. + if ($contentLC !== 'true' && $contentLC !== 'false' && $contentLC !== 'null') { + return; + } + + $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] !== \T_NS_SEPARATOR) { + return; + } + + $prevPrev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prev - 1), null, true); + if ($tokens[$prevPrev]['code'] === \T_STRING || $tokens[$prevPrev]['code'] === \T_NAMESPACE) { + return; + } + + $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($tokens[$next]['code'] === \T_NS_SEPARATOR) { + return; + } + } + + $fix = $phpcsFile->addFixableError( + 'The special PHP constant "%s" should not be fully qualified.', + $stackPtr, + 'Found', + [$contentLC] + ); + + if ($fix === true) { + if ($tokens[$stackPtr]['code'] === \T_NAME_FULLY_QUALIFIED) { + // PHPCS 4.x. + $phpcsFile->fixer->replaceToken($stackPtr, \ltrim($tokens[$stackPtr]['content'], '\\')); + } else { + // PHPCS 3.x. + $phpcsFile->fixer->replaceToken($prev, ''); + } + } + } +} diff --git a/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Exceptions/LogicException.php b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Exceptions/LogicException.php new file mode 100644 index 00000000..1bd890b1 --- /dev/null +++ b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Exceptions/LogicException.php @@ -0,0 +1,47 @@ + $cliArgs An array of values gathered from CLI args. + * @param bool $skipSettingStandard Whether to skip setting a standard to prevent + * the Config class trying to auto-discover a ruleset file. + * Should only be set to `true` for tests which actually test + * the ruleset auto-discovery. + * Note: there is no need to set this to `true` when a standard + * is being passed via the `$cliArgs`. Those settings will always + * respected. + * Defaults to `false`. Will result in the standard being set + * to "PSR1" if not provided via `$cliArgs`. + * @param bool $skipSettingReportWidth Whether to skip setting a report-width to prevent + * the Config class trying to auto-discover the screen width. + * Should only be set to `true` for tests which actually test + * the screen width auto-discovery. + * Note: there is no need to set this to `true` when a report-width + * is being passed via the `$cliArgs`. Those settings will always + * respected. + * Defaults to `false`. Will result in the reportWidth being set + * to "80" if not provided via `$cliArgs`. + * + * @return void + */ + public function __construct(array $cliArgs = [], $skipSettingStandard = false, $skipSettingReportWidth = false) + { + $this->skipSettingStandard = $skipSettingStandard; + $this->phpcsVersion = Helper::getVersion(); + + $this->resetSelectProperties(); + $this->preventReadingCodeSnifferConfFile(); + + parent::__construct($cliArgs); + + if ($skipSettingReportWidth !== true) { + $this->preventAutoDiscoveryScreenWidth(); + } + } + + /** + * Ensures the static properties in the Config class are reset to their default values + * when the ConfigDouble is no longer used. + * + * @since 1.1.0 + * + * @return void + */ + public function __destruct() + { + $this->setStaticConfigProperty('overriddenDefaults', []); + $this->setStaticConfigProperty('executablePaths', []); + $this->setStaticConfigProperty('configData', null); + $this->setStaticConfigProperty('configDataFile', null); + } + + /** + * Sets the command line values and optionally prevents a file system search for a custom ruleset. + * + * {@internal Note: `array` type declaration can't be added as the parent class does not have a type declaration + * for the parameter in the original method.} + * + * @since 1.1.0 + * + * @param array $args An array of command line arguments to set. + * + * @return void + */ + public function setCommandLineValues($args) + { + parent::setCommandLineValues($args); + + if ($this->skipSettingStandard !== true) { + $this->preventSearchingForRuleset(); + } + } + + /** + * Reset a few properties on the Config class to their default values. + * + * @since 1.1.0 + * + * @return void + */ + private function resetSelectProperties() + { + $this->setStaticConfigProperty('overriddenDefaults', []); + $this->setStaticConfigProperty('executablePaths', []); + } + + /** + * Prevent the values in a potentially available user-specific `CodeSniffer.conf` file + * from influencing the tests. + * + * This also prevents some file system calls which can influence the test runtime. + * + * @since 1.1.0 + * + * @return void + */ + private function preventReadingCodeSnifferConfFile() + { + $this->setStaticConfigProperty('configData', []); + $this->setStaticConfigProperty('configDataFile', ''); + } + + /** + * Prevent searching for a custom ruleset by setting a standard, but only if the test + * being run doesn't set a standard itself. + * + * This also prevents some file system calls which can influence the test runtime. + * + * The standard being set is the smallest one available so the ruleset initialization + * will be the fastest possible. + * + * @since 1.1.0 + * + * @return void + */ + private function preventSearchingForRuleset() + { + $overriddenDefaults = $this->getStaticConfigProperty('overriddenDefaults'); + if (isset($overriddenDefaults['standards']) === false) { + $this->standards = ['PSR1']; + $overriddenDefaults['standards'] = true; + } + + self::setStaticConfigProperty('overriddenDefaults', $overriddenDefaults); + } + + /** + * Prevent a call to stty to figure out the screen width, but only if the test being run + * doesn't set a report width itself. + * + * @since 1.1.0 + * + * @return void + */ + private function preventAutoDiscoveryScreenWidth() + { + $settings = $this->getSettings(); + if ($settings['reportWidth'] === 'auto') { + $this->reportWidth = self::DEFAULT_REPORT_WIDTH; + } + } + + /** + * Helper function to retrieve the value of a private static property on the Config class. + * + * Note: As of PHPCS 4.0, the "overriddenDefaults" property is no longer static, but this method + * will still handle this property. + * + * @since 1.1.0 + * + * @param string $name The name of the property to retrieve. + * + * @return mixed + */ + public function getStaticConfigProperty($name) + { + $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name); + $property->setAccessible(true); + + if ($name === 'overriddenDefaults' && \version_compare($this->phpcsVersion, '3.99.99', '>')) { + return $property->getValue($this); + } + + return $property->getValue(); + } + + /** + * Helper function to set the value of a private static property on the Config class. + * + * Note: As of PHPCS 4.0, the "overriddenDefaults" property is no longer static, but this method + * will still handle this property. + * + * @since 1.1.0 + * + * @param string $name The name of the property to set. + * @param mixed $value The value to set the property to. + * + * @return void + */ + public function setStaticConfigProperty($name, $value) + { + $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name); + $property->setAccessible(true); + + if ($name === 'overriddenDefaults' && \version_compare($this->phpcsVersion, '3.99.99', '>')) { + $property->setValue($this, $value); + } else { + $property->setValue(null, $value); + } + + $property->setAccessible(false); + } +} diff --git a/vendor/phpcsstandards/phpcsutils/PHPCSUtils/TestUtils/RulesetDouble.php b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/TestUtils/RulesetDouble.php new file mode 100644 index 00000000..10a3b6cb --- /dev/null +++ b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/TestUtils/RulesetDouble.php @@ -0,0 +1,57 @@ +getMessage()) !== 'ERROR: No sniffs were registered.') { + // Rethrow the exception to fail the test, as this is not the exception we expected. + throw $e; + } + } + } +} diff --git a/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/Constants.php b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/Constants.php new file mode 100644 index 00000000..d07620d2 --- /dev/null +++ b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/Constants.php @@ -0,0 +1,194 @@ + Array with information about the constant declaration. + * The format of the return value is: + * ```php + * array( + * 'scope' => string, // Public, private, or protected. + * 'scope_token' => integer|false, // The stack pointer to the scope keyword or + * // FALSE if the scope was not explicitly specified. + * 'is_final' => boolean, // TRUE if the final keyword was found. + * 'final_token' => integer|false, // The stack pointer to the final keyword + * // or FALSE if the const is not declared final. + * 'type' => string, // The type of the const (empty if no type specified). + * 'type_token' => integer|false, // The stack pointer to the start of the type + * // or FALSE if there is no type. + * 'type_end_token' => integer|false, // The stack pointer to the end of the type + * // or FALSE if there is no type. + * 'nullable_type' => boolean, // TRUE if the type is preceded by the + * // nullability operator. + * 'name_token' => integer, // The stack pointer to the constant name. + * // Note: for group declarations this points to the + * // name of the first constant. + * 'equal_token' => integer, // The stack pointer to the equal sign. + * // Note: for group declarations this points to the + * // equal sign of the first constant. + * ); + * ``` + * + * @throws \PHPCSUtils\Exceptions\TypeError If the $stackPtr parameter is not an integer. + * @throws \PHPCSUtils\Exceptions\OutOfBoundsStackPtr If the token passed does not exist in the $phpcsFile. + * @throws \PHPCSUtils\Exceptions\UnexpectedTokenType If the token passed is not a `T_CONST` token. + * @throws \PHPCSUtils\Exceptions\ValueError If the specified position is not an OO constant. + */ + public static function getProperties(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (\is_int($stackPtr) === false) { + throw TypeError::create(2, '$stackPtr', 'integer', $stackPtr); + } + + if (isset($tokens[$stackPtr]) === false) { + throw OutOfBoundsStackPtr::create(2, '$stackPtr', $stackPtr); + } + + if ($tokens[$stackPtr]['code'] !== \T_CONST) { + throw UnexpectedTokenType::create(2, '$stackPtr', 'T_CONST', $tokens[$stackPtr]['type']); + } + + if (Scopes::isOOConstant($phpcsFile, $stackPtr) === false) { + throw ValueError::create(2, '$stackPtr', 'must be the pointer to an OO constant'); + } + + if (Cache::isCached($phpcsFile, __METHOD__, $stackPtr) === true) { + return Cache::get($phpcsFile, __METHOD__, $stackPtr); + } + + $find = [\T_EQUAL, \T_SEMICOLON, \T_OPEN_CURLY_BRACKET, \T_CLOSE_CURLY_BRACKET, \T_CLOSE_TAG]; + $assignmentPtr = $phpcsFile->findNext($find, ($stackPtr + 1)); + if ($assignmentPtr === false || $tokens[$assignmentPtr]['code'] !== \T_EQUAL) { + // Probably a parse error. Don't cache the result. + throw ValueError::create(2, '$stackPtr', 'must be the pointer to an OO constant'); + } + + $namePtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($assignmentPtr - 1), ($stackPtr + 1), true); + + $returnValue = [ + 'scope' => 'public', + 'scope_token' => false, + 'is_final' => false, + 'final_token' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + 'name_token' => $namePtr, + 'equal_token' => $assignmentPtr, + ]; + + for ($i = ($stackPtr - 1);; $i--) { + // Skip over potentially large docblocks. + if ($tokens[$i]['code'] === \T_DOC_COMMENT_CLOSE_TAG + && isset($tokens[$i]['comment_opener']) + ) { + $i = $tokens[$i]['comment_opener']; + continue; + } + + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + switch ($tokens[$i]['code']) { + case \T_PUBLIC: + $returnValue['scope'] = 'public'; + $returnValue['scope_token'] = $i; + break; + + case \T_PROTECTED: + $returnValue['scope'] = 'protected'; + $returnValue['scope_token'] = $i; + break; + + case \T_PRIVATE: + $returnValue['scope'] = 'private'; + $returnValue['scope_token'] = $i; + break; + + case \T_FINAL: + $returnValue['is_final'] = true; + $returnValue['final_token'] = $i; + break; + + default: + // Any other token means that the start of the statement has been reached. + break 2; + } + } + + $type = ''; + $typeToken = false; + $typeEndToken = false; + $constantTypeTokens = Collections::constantTypeTokens(); + + // Now, let's check for a type. + for ($i = ($stackPtr + 1); $i < $namePtr; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + if ($tokens[$i]['code'] === \T_NULLABLE) { + $returnValue['nullable_type'] = true; + continue; + } + + if (isset($constantTypeTokens[$tokens[$i]['code']]) === true) { + $typeEndToken = $i; + if ($typeToken === false) { + $typeToken = $i; + } + + $type .= $tokens[$i]['content']; + } + } + + if ($type !== '' && $returnValue['nullable_type'] === true) { + $type = '?' . $type; + } + + $returnValue['type'] = $type; + $returnValue['type_token'] = $typeToken; + $returnValue['type_end_token'] = $typeEndToken; + + Cache::set($phpcsFile, __METHOD__, $stackPtr, $returnValue); + return $returnValue; + } +} diff --git a/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/FileInfo.php b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/FileInfo.php new file mode 100644 index 00000000..7e4540e8 --- /dev/null +++ b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/FileInfo.php @@ -0,0 +1,92 @@ + + */ + private static $bomDefinitions = [ + 'UTF-8' => 'efbbbf', + 'UTF-16 (BE)' => 'feff', + 'UTF-16 (LE)' => 'fffe', + ]; + + /** + * Determine whether the file under scan has a byte-order mark at the start. + * + * Inspired by similar code being used in a couple of PHPCS native sniffs. + * + * @since 1.1.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * + * @return string|false Name of the type of BOM found or FALSE when the file does not start with a BOM. + */ + public static function hasByteOrderMark(File $phpcsFile) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[0]['code'] !== \T_INLINE_HTML) { + return false; + } + + foreach (self::$bomDefinitions as $bomName => $expectedBomHex) { + $bomByteLength = (int) (\strlen($expectedBomHex) / 2); + $htmlBomHex = \bin2hex(\substr($tokens[0]['content'], 0, $bomByteLength)); + if ($htmlBomHex === $expectedBomHex) { + return $bomName; + } + } + + return false; + } + + /** + * Determine whether the file under scan has a shebang line at the start. + * + * @since 1.1.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * + * @return bool + */ + public static function hasSheBang(File $phpcsFile) + { + $tokens = $phpcsFile->getTokens(); + if ($tokens[0]['code'] !== \T_INLINE_HTML) { + return false; + } + + $start = 0; + $hasByteOrderMark = self::hasByteOrderMark($phpcsFile); + if ($hasByteOrderMark !== false) { + $start = (int) (\strlen(self::$bomDefinitions[$hasByteOrderMark]) / 2); + } + + return (\substr($tokens[0]['content'], $start, 2) === '#!'); + } +} diff --git a/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/FilePath.php b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/FilePath.php new file mode 100644 index 00000000..f08651ff --- /dev/null +++ b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/FilePath.php @@ -0,0 +1,154 @@ +getFileName()); + if ($fileName !== 'STDIN') { + $fileName = self::normalizeAbsolutePath($fileName); + } + + return \trim($fileName); + } + + /** + * Check whether the input was received via STDIN. + * + * @since 1.1.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * + * @return bool + */ + public static function isStdin(File $phpcsFile) + { + return (self::getName($phpcsFile) === 'STDIN'); + } + + /** + * Normalize an absolute path to forward slashes and to include a trailing slash for directories. + * + * @since 1.1.0 + * + * @param string $path Absolute file or directory path. + * + * @return string + */ + public static function normalizeAbsolutePath($path) + { + return self::trailingSlashIt(self::normalizeDirectorySeparators($path)); + } + + /** + * Normalize all directory separators to be a forward slash. + * + * {@internal We cannot rely on the OS on which PHPCS is being run to determine the + * the expected slashes, as the file name could also come from a text string in a + * tokenized file or have been set by an IDE...} + * + * @since 1.1.0 + * + * @param string $path File or directory path. + * + * @return string + */ + public static function normalizeDirectorySeparators($path) + { + return \strtr((string) $path, '\\', '/'); + } + + /** + * Ensure that a directory path ends on a trailing slash. + * + * Includes safeguard against adding a trailing slash to path ending on a file name. + * + * @since 1.1.0 + * + * @param string $path File or directory path. + * + * @return string + */ + public static function trailingSlashIt($path) + { + if (\is_string($path) === false || $path === '') { + return ''; + } + + $extension = ''; + $lastChar = \substr($path, -1); + if ($lastChar !== '/' && $lastChar !== '\\') { + // This may be a file, check if it has a file extension. + $extension = \pathinfo($path, \PATHINFO_EXTENSION); + } + + if ($extension !== '') { + return $path; + } + + return \rtrim((string) $path, '/\\') . '/'; + } + + /** + * Check whether one file/directory path starts with another path. + * + * Recommended to be used only when both paths are absolute. + * + * Note: this function does not normalize paths prior to comparing them. + * If this is needed, normalization should be done prior to passing + * the `$haystack` and `$needle` parameters to this function. + * + * Also note that this function does a case-sensitive comparison as most OS-es are case-sensitive. + * + * @since 1.1.0 + * + * @param string $haystack Path to examine. + * @param string $needle Partial path which the haystack path should start with. + * + * @return bool + */ + public static function startsWith($haystack, $needle) + { + return (\strncmp($haystack, $needle, \strlen($needle)) === 0); + } +} diff --git a/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/TypeString.php b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/TypeString.php new file mode 100644 index 00000000..1a5a6b15 --- /dev/null +++ b/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/TypeString.php @@ -0,0 +1,403 @@ + + */ + private static $keywordTypes = [ + 'array' => 'array', + 'bool' => 'bool', + 'callable' => 'callable', + 'false' => 'false', + 'float' => 'float', + 'int' => 'int', + 'iterable' => 'iterable', + 'mixed' => 'mixed', + 'never' => 'never', + 'null' => 'null', + 'object' => 'object', + 'parent' => 'parent', + 'self' => 'self', + 'static' => 'static', + 'string' => 'string', + 'true' => 'true', + 'void' => 'void', + ]; + + /** + * Retrieve a list of all PHP native keyword types. + * + * @since 1.1.0 + * + * @return array Key and value both contain the type name in lowercase. + */ + public static function getKeywordTypes() + { + return self::$keywordTypes; + } + + /** + * Check if a singular type is a PHP native keyword based type. + * + * @since 1.1.0 + * + * @param string $type The singular type. + * + * @return bool + */ + public static function isKeyword($type) + { + if (\is_string($type) === false) { + return false; + } + + $typeLC = \strtolower(\trim($type)); + return isset(self::$keywordTypes[$typeLC]); + } + + /** + * Normalize the case for a single type. + * + * - Types which are recognized PHP "keyword" types will be returned in lowercase. + * - Class/Interface/Enum names will be returned in their original case. + * + * @since 1.1.0 + * + * @param string $type Type to normalize the case for. + * + * @return string The case-normalized type or an empty string if the input was invalid. + */ + public static function normalizeCase($type) + { + if (\is_string($type) === false) { + return ''; + } + + if (self::isKeyword($type)) { + return \strtolower($type); + } + + return $type; + } + + /** + * Check if a type string represents a plain, singular type. + * + * Note: Nullable types are not considered plain, singular types for the purposes of this method. + * + * @since 1.1.0 + * + * @param string $typeString Type string. + * + * @return bool + */ + public static function isSingular($typeString) + { + if (\is_string($typeString) === false) { + return false; + } + + $typeString = \trim($typeString); + + return empty($typeString) === false + && \strpos($typeString, '?') === false + && \strpos($typeString, '|') === false + && \strpos($typeString, '&') === false + && \strpos($typeString, '(') === false + && \strpos($typeString, ')') === false; + } + + /** + * Check if a type string represents a nullable type. + * + * A nullable type in the context of this method is a type which + * - starts with the nullable operator and has something after it which is being made nullable; + * - or contains `null` as part of a union or DNF type. + * + * A stand-alone `null` type is not considered a nullable type, but a singular type. + * + * @since 1.1.0 + * + * @param string $typeString Type string. + * + * @return bool + */ + public static function isNullable($typeString) + { + if (\is_string($typeString) === false) { + return false; + } + + $typeString = \trim($typeString); + if (empty($typeString) === true) { + return false; + } + + // Check for plain nullable type with something which is being made nullable. + if (\preg_match('`^\?\s*[^|&()?\s]+`', $typeString) === 1) { + return true; + } + + // Check for nullable union type. + $matched = \preg_match( + '`(?^|[^|&(?\s]+\s*\|)\s*null\s*(?\|\s*[^|&)?\s]+|$)`i', + $typeString, + $matches + ); + return ($matched === 1 + && (empty($matches['before']) === false || empty($matches['after']) === false)); + } + + /** + * Check if a type string represents a pure union type. + * + * Note: DNF types are not considered union types for the purpose of this method. + * + * @since 1.1.0 + * + * @param string $typeString Type string. + * + * @return bool + */ + public static function isUnion($typeString) + { + return \is_string($typeString) + && \strpos($typeString, '?') === false + && \strpos($typeString, '|') !== false + && \strpos($typeString, '&') === false + && \strpos($typeString, '(') === false + && \strpos($typeString, ')') === false + // Make sure there is always something before and after each |. + && \preg_match('`^[^|&()?\s]+(\s*\|\s*[^|&()?\s]+)+$`', $typeString) === 1; + } + + /** + * Check if a type string represents a pure intersection type. + * + * Note: DNF types are not considered intersection types for the purpose of this method. + * + * @since 1.1.0 + * + * @param string $typeString Type string. + * + * @return bool + */ + public static function isIntersection($typeString) + { + return \is_string($typeString) + && \strpos($typeString, '?') === false + && \strpos($typeString, '|') === false + && \strpos($typeString, '&') !== false + && \strpos($typeString, '(') === false + && \strpos($typeString, ')') === false + // Make sure there is always something before and after each &. + && \preg_match('`^[^|&()?\s]+(\s*&\s*[^|&()?\s]+)+$`', $typeString) === 1; + } + + /** + * Check if a type string represents a disjunctive normal form (DNF) type. + * + * This check for a strict + * + * @since 1.1.0 + * + * @param string $typeString Type string. + * + * @return bool + */ + public static function isDNF($typeString) + { + return \is_string($typeString) + && \strpos($typeString, '?') === false + && \strpos($typeString, '|') !== false + && \strpos($typeString, '&') !== false + && \strpos($typeString, '(') !== false + && \strpos($typeString, ')') !== false + // Now make sure that it is not a definitely invalid format. + && \preg_match(self::INVALID_DNF_REGEX, $typeString) !== 1; + } + + /** + * Split a type string to its individual types and optionally normalize the case of the types. + * + * @since 1.1.0 + * + * @param string $typeString Type to split. + * @param bool $normalize Whether or not to normalize the case of types. + * Defaults to true. + * + * @return array List containing all seen types in the order they were encountered. + * + * @throws \PHPCSUtils\Exceptions\TypeError If passed $typeString is not a string. + */ + public static function toArray($typeString, $normalize = true) + { + if (\is_string($typeString) === false) { + throw TypeError::create(1, '$typeString', 'string', $typeString); + } + + if (\trim($typeString) === '') { + return []; + } + + $addNull = false; + if ($typeString[0] === '?') { + $addNull = true; + $typeString = \substr($typeString, 1); + } + + $typeString = \preg_replace('`\s+`', '', $typeString); + $types = \preg_split('`[|&()]+`', $typeString, -1, \PREG_SPLIT_NO_EMPTY); + + // Normalize the types. + if ($normalize === true) { + $types = \array_map([__CLASS__, 'normalizeCase'], $types); + } + + if ($addNull === true) { + \array_unshift($types, 'null'); + } + + return $types; + } + + /** + * Split a type string to the unique types included and optionally normalize the case of the types. + * + * @since 1.1.0 + * + * @param string $typeString Type to split. + * @param bool $normalize Whether or not to normalize the case of types. + * Defaults to true. + * + * @return array Associative array with the unique types as both the key as well as the value. + * + * @throws \PHPCSUtils\Exceptions\TypeError If passed $typeString is not a string. + */ + public static function toArrayUnique($typeString, $normalize = true) + { + $types = self::toArray($typeString, $normalize); + return \array_combine($types, $types); + } + + /** + * Filter a list of types down to only the keyword based types. + * + * @since 1.1.0 + * + * @param array $types Array of types. + * Typically, this is an array as retrieved from the + * {@see TypeString::toArray()} method or the + * {@see TypeString::toArrayUnique()} method. + * + * @return array Array with only the PHP native keyword based types. + * The result may be an empty array if the input array didn't contain + * any keyword based types or if the input was invalid. + */ + public static function filterKeywordTypes(array $types) + { + return \array_filter($types, [__CLASS__, 'isKeyword']); + } + + /** + * Filter a list of types down to only the OO name based types. + * + * @since 1.1.0 + * + * @param array $types Array of types. + * Typically, this is an array as retrieved from the + * {@see TypeString::toArray()} method or the + * {@see TypeString::toArrayUnique()} method. + * + * @return array Array with only the OO name based types. + * The result may be an empty array if the input array didn't contain + * any OO name based types or if the input was invalid. + */ + public static function filterOOTypes(array $types) + { + return \array_filter( + $types, + static function ($type) { + return \is_string($type) === true && self::isKeyword($type) === false; + } + ); + } +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Arrays/ArrayIndentStandard.xml b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Arrays/ArrayIndentStandard.xml new file mode 100644 index 00000000..0312a70f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Arrays/ArrayIndentStandard.xml @@ -0,0 +1,107 @@ + + + + + + + [ + 1, + 2, +]; + +if ($condition) { + $a = + [ + 1, + 2, + ]; +} + + ]]> + + + [ + 1, + 2, + ]; +} + ]]> + + + + + + + + 1, + 2, + 3, +); + ]]> + + + 1, + 2, + 3, +); + ]]> + + + + + + + + +]; + ]]> + + + ]; + ]]> + + + + + + + + ); + ]]> + + + ); + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Strings/UnnecessaryHeredocStandard.xml b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Strings/UnnecessaryHeredocStandard.xml new file mode 100644 index 00000000..e0ca14f4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Strings/UnnecessaryHeredocStandard.xml @@ -0,0 +1,39 @@ + + + + + + + <<<'EOD' +some text +EOD; + ]]> + + + << +some text +EOD; + ]]> + + + + + <<<"EOD" +some $text +EOD; + ]]> + + + <<<"EOD" +some text +EOD; + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/HereNowdocIdentifierSpacingStandard.xml b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/HereNowdocIdentifierSpacingStandard.xml new file mode 100644 index 00000000..66759bf5 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/HereNowdocIdentifierSpacingStandard.xml @@ -0,0 +1,23 @@ + + + + + + + << +some text +EOD; + ]]> + + + <<< END +some text +END; + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryHeredocSniff.php b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryHeredocSniff.php new file mode 100644 index 00000000..aa81dc2e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryHeredocSniff.php @@ -0,0 +1,145 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Sniffs\Strings; + +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\Sniff; + +class UnnecessaryHeredocSniff implements Sniff +{ + + /** + * Escape chars which are supported in heredocs, but not in nowdocs. + * + * @var array + */ + private $escapeChars = [ + // Octal sequences. + '\0', + '\1', + '\2', + '\3', + '\4', + '\5', + '\6', + '\7', + + // Various whitespace and the escape char. + '\n', + '\r', + '\t', + '\v', + '\e', + '\f', + + // Hex and unicode sequences. + '\x', + '\u', + ]; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return [T_START_HEREDOC]; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + // Just to be safe. Shouldn't be possible as in that case, the opener shouldn't be tokenized + // to T_START_HEREDOC by PHP. + return; // @codeCoverageIgnore + } + + $closer = $tokens[$stackPtr]['scope_closer']; + $body = ''; + + // Collect all the tokens within the heredoc body. + for ($i = ($stackPtr + 1); $i < $closer; $i++) { + $body .= $tokens[$i]['content']; + } + + $tokenizedBody = token_get_all(sprintf("", $body)); + foreach ($tokenizedBody as $ptr => $bodyToken) { + if (is_array($bodyToken) === false) { + continue; + } + + if ($bodyToken[0] === T_DOLLAR_OPEN_CURLY_BRACES + || $bodyToken[0] === T_VARIABLE + ) { + // Contains interpolation or expression. + $phpcsFile->recordMetric($stackPtr, 'Heredoc contains interpolation or expression', 'yes'); + return; + } + + if ($bodyToken[0] === T_CURLY_OPEN + && is_array($tokenizedBody[($ptr + 1)]) === false + && $tokenizedBody[($ptr + 1)] === '$' + ) { + // Contains interpolation or expression. + $phpcsFile->recordMetric($stackPtr, 'Heredoc contains interpolation or expression', 'yes'); + return; + } + }//end foreach + + $phpcsFile->recordMetric($stackPtr, 'Heredoc contains interpolation or expression', 'no'); + + // Check for escape sequences which aren't supported in nowdocs. + foreach ($this->escapeChars as $testChar) { + if (strpos($body, $testChar) !== false) { + return; + } + } + + $warning = 'Detected heredoc without interpolation or expressions. Use nowdoc syntax instead'; + + $fix = $phpcsFile->addFixableWarning($warning, $stackPtr, 'Found'); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + $identifier = trim(ltrim($tokens[$stackPtr]['content'], '<')); + $replaceWith = "'".trim($identifier, '"')."'"; + $replacement = str_replace($identifier, $replaceWith, $tokens[$stackPtr]['content']); + $phpcsFile->fixer->replaceToken($stackPtr, $replacement); + + for ($i = ($stackPtr + 1); $i < $closer; $i++) { + $content = $tokens[$i]['content']; + $content = str_replace(['\\$', '\\\\'], ['$', '\\'], $content); + if ($tokens[$i]['content'] !== $content) { + $phpcsFile->fixer->replaceToken($i, $content); + } + } + + $phpcsFile->fixer->endChangeset(); + } + + }//end process() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php new file mode 100644 index 00000000..ca595743 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php @@ -0,0 +1,69 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace; + +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\Sniff; + +class HereNowdocIdentifierSpacingSniff implements Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return [ + T_START_HEREDOC, + T_START_NOWDOC, + ]; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (strpos($tokens[$stackPtr]['content'], ' ') === false + && strpos($tokens[$stackPtr]['content'], "\t") === false + ) { + // Nothing to do. + $phpcsFile->recordMetric($stackPtr, 'Heredoc/nowdoc identifier', 'no space between <<< and ID'); + return; + } + + $phpcsFile->recordMetric($stackPtr, 'Heredoc/nowdoc identifier', 'space between <<< and ID'); + + $error = 'There should be no space between the <<< and the heredoc/nowdoc identifier string. Found: %s'; + $data = [$tokens[$stackPtr]['content']]; + + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceFound', $data); + if ($fix === true) { + $replacement = str_replace([' ', "\t"], '', $tokens[$stackPtr]['content']); + $phpcsFile->fixer->replaceToken($stackPtr, $replacement); + } + + }//end process() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.10.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.10.inc new file mode 100644 index 00000000..d5ab20e3 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.10.inc @@ -0,0 +1,6 @@ + + + + + + + + + +/* + * Test empty statement: no code between PHP open and close tag. + */ + + + + + + + + + + + + + + + + + + + true, +}; diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed new file mode 100644 index 00000000..6bf8b212 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed @@ -0,0 +1,80 @@ + + + + +/* + * Test empty statement: no code between PHP open and close tag. + */ + + + + + + + + + + + + + + + + + + true, +}; diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc new file mode 100644 index 00000000..a9f895d7 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc @@ -0,0 +1,27 @@ + + + + + +/* + * Test empty statement: no code between PHP open and close tag. + */ + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed new file mode 100644 index 00000000..fd27d0a2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed @@ -0,0 +1,23 @@ + + + + + +/* + * Test empty statement: no code between PHP open and close tag. + */ + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.1.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.1.inc new file mode 100644 index 00000000..58b604f7 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.1.inc @@ -0,0 +1,13 @@ + 0; i--) print 'hello'; + +while (something) print 'hello'; + +do { + i--; +} while (something); + +do i++; while (i < 5); + +SomeClass.prototype.for = function() { + // do something +}; + +if ($("#myid").rotationDegrees()=='90') + $('.modal').css({'transform': 'rotate(90deg)'}); + +if ($("#myid").rotationDegrees()=='90') + $foo = {'transform': 'rotate(90deg)'}; + +if (something) { + alert('hello'); +} else /* comment */ if (somethingElse) alert('hi'); diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed new file mode 100644 index 00000000..050a406b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed @@ -0,0 +1,44 @@ + + +if (something) { print 'hello'; +} + +if (something) { + print 'hello'; +} else { print 'hi'; +} + +if (something) { + print 'hello'; +} else if (something) { print 'hi'; +} + +for (i; i > 0; i--) { print 'hello'; +} + +while (something) { print 'hello'; +} + +do { + i--; +} while (something); + +do { i++; +} while (i < 5); + +SomeClass.prototype.for = function() { + // do something +}; + +if ($("#myid").rotationDegrees()=='90') { + $('.modal').css({'transform': 'rotate(90deg)'}); +} + +if ($("#myid").rotationDegrees()=='90') { + $foo = {'transform': 'rotate(90deg)'}; +} + +if (something) { + alert('hello'); +} else /* comment */ if (somethingElse) { alert('hi'); +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.2.js b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.2.js new file mode 100644 index 00000000..e26c3312 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.2.js @@ -0,0 +1,5 @@ +// Intentional parse error (missing closing parenthesis). +// This should be the only test in this file. +// Testing that the sniff is *not* triggered. + +do i++; while (i < 5 diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.3.js b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.3.js new file mode 100644 index 00000000..9ccedcda --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.3.js @@ -0,0 +1,5 @@ +// Intentional parse error (missing opening parenthesis). +// This should be the only test in this file. +// Testing that the sniff is *not* triggered. + +do i++; while diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc new file mode 100644 index 00000000..b3d9bbc7 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc @@ -0,0 +1 @@ +getArray($one, $two,$three),$this->arrayMap); +$this->error($obj->getCode(),$obj->getMessage(),$obj->getFile(),$obj->getLine()); + +make_foo($string /*the string*/ , true /*test*/); +make_foo($string/*the string*/ , /*test*/ true); +make_foo($string /*the string*/, /*test*/ true); + +class MyClass { + function myFunction() { + blah($foo, "{{$config['host']}}", "{$config}", "hi there{}{}{{{}{}{}}"); + } +} + +// Function definition, not function call, so should be ignored +function &myFunction($arg1=1,$arg2=2) +{ +} + +return array_udiff( + $foo, + $bar, + function($a, $b) { + $foo='bar'; + return $foo; + } +); + +var_dump(<<{$var}($foo,$bar); + +(function ($a, $b) { + return function ($c, $d) use ($a, $b) { + echo $a, $b, $c, $d; + }; +})('a','b')('c','d'); + +my_function_call( + 'a' + /* Comment */ + ,'b' + , 'c' // Comment. + ,'d' + ,'e' // phpcs:ignore Standard.Category.Sniff -- for reasons. + , 'f' +); + +$foobar = php73_function_call_trailing_comma( + $foo, + $bar, +); + +$foobar = functionCallAnonClassParam( + new class() { + public $foo=1; + public function methodName($param='foo',$paramTwo='bar') { + $bar=false; + $foo = array(1,2,3); + } + }, + $args=array(), +); + +$result = myFunction(param1: $arg1, param2: $arg2); +$result = myFunction(param1: $arg1 , param2:$arg2); +$result = myFunction(param1: $arg1, param2:$arg2, param3: $arg3,param4:$arg4, param5:$arg5); + +class Testing extends Bar +{ + public static function baz($foo, $bar) + { + $a = new parent($foo, $bar); + $a = new parent($foo ,$bar); + } +} + +// Ignore spacing after PHP 7.3+ trailing comma in single-line function calls to prevent fixer conflicts. +// This is something which should be decided by a sniff dealing with the function call parentheses. +$foo = new MyClass($obj, 'getMethod',); +$foo = new MyClass($obj, 'getMethod', ); +$foo = new MyClass($obj, 'getMethod', ); +$foo = new MyClass( + $obj, + 'getMethod', +); + +#[AttributeName(1, 2)] +#[AttributeName(1,2)] + +$callable = myCallable(...); + +// Skip over PHP 7.4 arrow functions. +// While any commas belonging to the code within the arrow function would always need to be within parentheses +// or within a short array, so there aren't any false positives, the sniff also does not need to examine these, +// so will be more efficient skipping over arrow functions. +$foobar = functionCallFnParamA( + fn ($foo,$bar) => [1,2,3], + $args, +); + +$foobar = functionCallFnParamB(fn ($foo,$bar) => [1,2,3] ,$args); +$foobar = functionCallFnParamC($args, fn ($foo,$bar) => [1,2,3] , ); + +// Ignore spacing within PHP 8.0 match control structures, which may have their own rules. +$foobar = functionCallMatchParam( + match($foo) { + 1,2,3 => 'something',4,5,6 => 'else',default => 'works' + } , // But check the spacing again once the match expression has finished. + $args +); diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.1.inc.fixed b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.1.inc.fixed new file mode 100644 index 00000000..a50f695e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.1.inc.fixed @@ -0,0 +1,199 @@ +getArray($one, $two, $three), $this->arrayMap); +$this->error($obj->getCode(), $obj->getMessage(), $obj->getFile(), $obj->getLine()); + +make_foo($string /*the string*/, true /*test*/); +make_foo($string/*the string*/, /*test*/ true); +make_foo($string /*the string*/, /*test*/ true); + +class MyClass { + function myFunction() { + blah($foo, "{{$config['host']}}", "{$config}", "hi there{}{}{{{}{}{}}"); + } +} + +// Function definition, not function call, so should be ignored +function &myFunction($arg1=1,$arg2=2) +{ +} + +return array_udiff( + $foo, + $bar, + function($a, $b) { + $foo='bar'; + return $foo; + } +); + +var_dump(<<{$var}($foo, $bar); + +(function ($a, $b) { + return function ($c, $d) use ($a, $b) { + echo $a, $b, $c, $d; + }; +})('a', 'b')('c', 'd'); + +my_function_call( + 'a', + /* Comment */ + 'b', + 'c', // Comment. + 'd', + 'e', // phpcs:ignore Standard.Category.Sniff -- for reasons. + 'f' +); + +$foobar = php73_function_call_trailing_comma( + $foo, + $bar, +); + +$foobar = functionCallAnonClassParam( + new class() { + public $foo=1; + public function methodName($param='foo',$paramTwo='bar') { + $bar=false; + $foo = array(1,2,3); + } + }, + $args=array(), +); + +$result = myFunction(param1: $arg1, param2: $arg2); +$result = myFunction(param1: $arg1, param2:$arg2); +$result = myFunction(param1: $arg1, param2:$arg2, param3: $arg3, param4:$arg4, param5:$arg5); + +class Testing extends Bar +{ + public static function baz($foo, $bar) + { + $a = new parent($foo, $bar); + $a = new parent($foo, $bar); + } +} + +// Ignore spacing after PHP 7.3+ trailing comma in single-line function calls to prevent fixer conflicts. +// This is something which should be decided by a sniff dealing with the function call parentheses. +$foo = new MyClass($obj, 'getMethod',); +$foo = new MyClass($obj, 'getMethod', ); +$foo = new MyClass($obj, 'getMethod', ); +$foo = new MyClass( + $obj, + 'getMethod', +); + +#[AttributeName(1, 2)] +#[AttributeName(1, 2)] + +$callable = myCallable(...); + +// Skip over PHP 7.4 arrow functions. +// While any commas belonging to the code within the arrow function would always need to be within parentheses +// or within a short array, so there aren't any false positives, the sniff also does not need to examine these, +// so will be more efficient skipping over arrow functions. +$foobar = functionCallFnParamA( + fn ($foo,$bar) => [1,2,3], + $args, +); + +$foobar = functionCallFnParamB(fn ($foo,$bar) => [1,2,3], $args); +$foobar = functionCallFnParamC($args, fn ($foo,$bar) => [1,2,3], ); + +// Ignore spacing within PHP 8.0 match control structures, which may have their own rules. +$foobar = functionCallMatchParam( + match($foo) { + 1,2,3 => 'something',4,5,6 => 'else',default => 'works' + }, // But check the spacing again once the match expression has finished. + $args +); diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.2.inc new file mode 100644 index 00000000..f0ff633e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.2.inc @@ -0,0 +1,7 @@ + +
+ +
+ +
+ +
+ 30, + 'jan', 'mar', 'may', 'jul', 'aug', 'oct', 'dec' => 31, + 'feb' => is_leap_year($year) ? 29 : 28, + default => throw new InvalidArgumentException("Invalid month"), + } +} + + +function complexityFourteenWithMatch() +{ + return match(strtolower(substr($monthName, 0, 3))) { + 'jan' => 31, + 'feb' => is_leap_year($year) ? 29 : 28, + 'mar' => 31, + 'apr' => 30, + 'may' => 31, + 'jun' => 30, + 'jul' => 31, + 'aug' => 31, + 'sep' => 30, + 'oct' => 31, + 'nov' => 30, + 'dec' => 31, + default => throw new InvalidArgumentException("Invalid month"), + }; +} + + +function complexitySevenWithNullSafeOperator() +{ + $foo = $object1->getX()?->getY()?->getZ(); + $bar = $object2->getX()?->getY()?->getZ(); + $baz = $object3->getX()?->getY()?->getZ(); +} + + +function complexityElevenWithNullSafeOperator() +{ + $foo = $object1->getX()?->getY()?->getZ(); + $bar = $object2->getX()?->getY()?->getZ(); + $baz = $object3->getX()?->getY()?->getZ(); + $bacon = $object4->getX()?->getY()?->getZ(); + $bits = $object5->getX()?->getY()?->getZ(); +} + +abstract class AbstractClass { + abstract public function sniffShouldIgnoreAbstractMethods(); +} + +interface MyInterface { + public function sniffShouldIgnoreInterfaceMethods(); +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc new file mode 100644 index 00000000..9658af30 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc @@ -0,0 +1,7 @@ + 5); + } + break; + } + } +} + +function nestingTen() +{ + if ($condition) { + echo 'hi'; + switch ($condition) + { + case '1': + if ($condition === '1') { + if ($cond) { + switch ($cond) { + case '1': + if ($cond === '1') { + foreach ($conds as $cond) { + if ($cond === 'hi') { + echo 'hi'; + } + } + } + break; + } + } + } + break; + } + } +} + +function nestingEleven() +{ + if ($condition) { + echo 'hi'; + switch ($condition) + { + case '1': + if ($condition === '1') { + if ($cond) { + try { + if ( $cond === '1' ) { + for ( $i = 0; $i < 10; $i ++ ) { + while ($i < 5) { + if ( $cond === 'hi' ) { + match ( $cond ) { + 'hi' => 'something', + }; + } + } + } + } + } catch (Exception $e) {} + } + } + break; + } + } +} + +abstract class AbstractClass { + abstract public function sniffShouldIgnoreAbstractMethods(); +} + +interface MyInterface { + public function sniffShouldIgnoreInterfaceMethods(); +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc new file mode 100644 index 00000000..9658af30 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc @@ -0,0 +1,7 @@ +define('bar'); +$foo->getBar()->define('foo'); +Foo::define('bar'); + +class ClassConstBowOutTest { + const /* comment */ abc = 1; + const // phpcs:ignore Standard.Category.Sniff + some_constant = 2; +} + +$foo->getBar()?->define('foo'); + +// PHP 8.3 introduces typed constants. +class TypedConstants { + + const MyClass MYCONST = new MyClass; + const int VALID_NAME = 0; + final public const INT invalid_name = 0; + const FALSE false = false; // Yes, false can be used as a constant name, don't ask. + final protected const array ARRAY = array(); // Same goes for array. +} + +define /* comment */ ( /* comment */ 'CommentsInUnconventionalPlaces', 'value' ); + +define +// comment +( + // phpcs:ignore Stnd.Cat.SniffName -- for reasons. + 'CommentsInUnconventionalPlaces', + 'value' +); + +$foo-> /* comment */ define('bar'); +$foo?-> +// phpcs:ignore Stnd.Cat.SniffName -- for reasons. +define('bar'); + +const DEFINE = 'value'; + +#[Define('some param')] +class MyClass {} + +#[ + AttributeA, + define('some param') +] +class MyClass {} + +const MixedCase = 1; + +define('lower_case_name', 'value'); +define($var, 'sniff should bow out'); +define(constantName(), 'sniff should bow out'); +define($obj->constantName(), 'sniff should bow out'); +define(MyClass::constantName(), 'sniff should bow out'); +define(condition() ? 'name1' : 'name2', 'sniff should bow out'); + +$callable = define(...); + +// Valid if outside the global namespace. Sniff should bow out. +function define($param) {} + +class MyClass { + public function define($param) {} +} + +$a = ($cond) ? DEFINE : SOMETHING_ELSE; + +$object = new Define('value'); diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc new file mode 100644 index 00000000..4136912d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc @@ -0,0 +1,7 @@ + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc new file mode 100644 index 00000000..301f6efd --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc @@ -0,0 +1,174 @@ +NULL = 7; + +use Zend\Log\Writer\NULL as NullWriter; +new \Zend\Log\Writer\NULL(); + +namespace False; + +class True extends Null implements False {} + +use True\Something; +use Something\True; +class MyClass +{ + public function myFunction() + { + $var = array('foo' => new True()); + } +} + +$x = $f?FALSE:true; +$x = $f? FALSE:true; + +class MyClass +{ + // Spice things up a little. + const TRUE = false; +} + +var_dump(MyClass::TRUE); + +function tRUE() {} + +$input->getFilterChain()->attachByName('Null', ['type' => Null::TYPE_STRING]); + +// Issue #3332 - ignore type declarations, but not default values. +class TypedThings { + const MYCONST = FALSE; + + public int|FALSE $int = FALSE; + public Type|NULL $int = new MyObj(NULL); + + private function typed(int|FALSE $param = NULL, Type|NULL $obj = new MyObj(FALSE)) : string|FALSE|NULL + { + if (TRUE === FALSE) { + return NULL; + } + } +} + +$cl = function (int|FALSE $param = NULL, Type|NULL $obj = new MyObj(FALSE)) : string|FALSE|NULL {}; + +// Adding some extra tests to safeguard that function declarations which don't create scope are handled correctly. +interface InterfaceMethodsWithReturnTypeNoScopeOpener { + private function typed($param = TRUE) : string|FALSE|NULL; +} + +abstract class ClassMethodsWithReturnTypeNoScopeOpener { + abstract public function typed($param = FALSE) : TRUE; +} + +// Additional tests to safeguard improved property type skip logic. +readonly class Properties { + use SomeTrait { + sayHello as private myPrivateHello; + } + + public Type|FALSE|NULL $propertyA = array( + 'itemA' => TRUE, + 'itemB' => FALSE, + 'itemC' => NULL, + ), $propertyB = FALSE; + + protected \FullyQualified&Partially\Qualified&namespace\Relative $propertyC; + var ?TRUE $propertyD; + static array|callable|FALSE|self|parent $propertyE = TRUE; + private + // phpcs:ignore Stnd.Cat.Sniff -- for reasons. + TRUE /*comment*/ + $propertyF = TRUE; + + public function __construct( + public FALSE|NULL $promotedPropA, + readonly callable|TRUE $promotedPropB, + ) { + static $var; + echo static::class; + static::foo(); + $var = $var instanceof static; + $obj = new static(); + } + + public static function foo(): static|self|FALSE { + $callable = static function() {}; + } +} + +// PHP 8.3 introduces typed constants. +class TypedConstants { + const MyClass|NULL|TRUE|FALSE MYCONST = FALSE; +} + +// Global constants can not be typed. +const MYCONST = TRUE; + +class SkipOverPHP82DNFTypes { + protected (\FullyQualified&Partially\Qualified)|TRUE $propertyC; +} + +class SkipOverPHP84FinalProperties { + final MyType|FALSE $propA; + private static final NULL|MyClass $propB; +} + +// PHP 8.4 asymmetric visibility +class WithAsym { + + private(set) NULL|TRUE $asym1 = TRUE; + + public private(set) ?bool $asym2 = FALSE; + + protected(set) FALSE|string|null $asym3 = NULL; + + public protected(set) Type|NULL|bool $asym4 = TRUE; +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc.fixed b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc.fixed new file mode 100644 index 00000000..5dcd342d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc.fixed @@ -0,0 +1,174 @@ +NULL = 7; + +use Zend\Log\Writer\NULL as NullWriter; +new \Zend\Log\Writer\NULL(); + +namespace False; + +class True extends Null implements False {} + +use True\Something; +use Something\True; +class MyClass +{ + public function myFunction() + { + $var = array('foo' => new True()); + } +} + +$x = $f?false:true; +$x = $f? false:true; + +class MyClass +{ + // Spice things up a little. + const TRUE = false; +} + +var_dump(MyClass::TRUE); + +function tRUE() {} + +$input->getFilterChain()->attachByName('Null', ['type' => Null::TYPE_STRING]); + +// Issue #3332 - ignore type declarations, but not default values. +class TypedThings { + const MYCONST = false; + + public int|FALSE $int = false; + public Type|NULL $int = new MyObj(null); + + private function typed(int|FALSE $param = null, Type|NULL $obj = new MyObj(false)) : string|FALSE|NULL + { + if (true === false) { + return null; + } + } +} + +$cl = function (int|FALSE $param = null, Type|NULL $obj = new MyObj(false)) : string|FALSE|NULL {}; + +// Adding some extra tests to safeguard that function declarations which don't create scope are handled correctly. +interface InterfaceMethodsWithReturnTypeNoScopeOpener { + private function typed($param = true) : string|FALSE|NULL; +} + +abstract class ClassMethodsWithReturnTypeNoScopeOpener { + abstract public function typed($param = false) : TRUE; +} + +// Additional tests to safeguard improved property type skip logic. +readonly class Properties { + use SomeTrait { + sayHello as private myPrivateHello; + } + + public Type|FALSE|NULL $propertyA = array( + 'itemA' => true, + 'itemB' => false, + 'itemC' => null, + ), $propertyB = false; + + protected \FullyQualified&Partially\Qualified&namespace\Relative $propertyC; + var ?TRUE $propertyD; + static array|callable|FALSE|self|parent $propertyE = true; + private + // phpcs:ignore Stnd.Cat.Sniff -- for reasons. + TRUE /*comment*/ + $propertyF = true; + + public function __construct( + public FALSE|NULL $promotedPropA, + readonly callable|TRUE $promotedPropB, + ) { + static $var; + echo static::class; + static::foo(); + $var = $var instanceof static; + $obj = new static(); + } + + public static function foo(): static|self|FALSE { + $callable = static function() {}; + } +} + +// PHP 8.3 introduces typed constants. +class TypedConstants { + const MyClass|NULL|TRUE|FALSE MYCONST = false; +} + +// Global constants can not be typed. +const MYCONST = true; + +class SkipOverPHP82DNFTypes { + protected (\FullyQualified&Partially\Qualified)|TRUE $propertyC; +} + +class SkipOverPHP84FinalProperties { + final MyType|FALSE $propA; + private static final NULL|MyClass $propB; +} + +// PHP 8.4 asymmetric visibility +class WithAsym { + + private(set) NULL|TRUE $asym1 = true; + + public private(set) ?bool $asym2 = false; + + protected(set) FALSE|string|null $asym3 = null; + + public protected(set) Type|NULL|bool $asym4 = true; +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.2.inc new file mode 100644 index 00000000..c61a0a50 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.2.inc @@ -0,0 +1,4 @@ +bar} +END; + +$heredoc = <<< "END" +some ${beers::softdrink} +END; + +$heredoc = <<< END +{${$object->getName()}} text +END; + +$heredoc = <<<"END" +some {${getName()}} +END; + +$heredoc = <<baz()()} +END; + +$heredoc = <<values[3]->name} text +END; + +$heredoc = <<<"END" +some ${$bar} +END; + +$heredoc = <<bar} text +END; + +$heredoc = <<<"END" +${foo["${bar}"]} text +END; + +$heredoc = <<{${'a'}}} text +END; + +$heredoc = <<{$baz[1]}} +END; + +$heredoc = <<john's wife greeted $people->robert. +END; + +$heredoc = <<bar} +END; + +$heredoc = <<< "END" +some ${beers::softdrink} +END; + +$heredoc = <<< END +{${$object->getName()}} text +END; + +$heredoc = <<<"END" +some {${getName()}} +END; + +$heredoc = <<baz()()} +END; + +$heredoc = <<values[3]->name} text +END; + +$heredoc = <<<"END" +some ${$bar} +END; + +$heredoc = <<bar} text +END; + +$heredoc = <<<"END" +${foo["${bar}"]} text +END; + +$heredoc = <<{${'a'}}} text +END; + +$heredoc = <<{$baz[1]}} +END; + +$heredoc = <<john's wife greeted $people->robert. +END; + +$heredoc = <<bar} + END; + +$heredoc = <<< "END" + some ${beers::softdrink} + END; + +$heredoc = <<< END + {${$object->getName()}} text + END; + +$heredoc = <<<"END" + some {${getName()}} + END; + +$heredoc = <<baz()()} + END; + +$heredoc = <<values[3]->name} text + END; + +$heredoc = <<<"END" + some ${$bar} + END; + +$heredoc = <<bar} text + END; + +$heredoc = <<<"END" + ${foo["${bar}"]} text + END; + +$heredoc = <<{${'a'}}} text + END; + +$heredoc = <<{$baz[1]}} + END; + +$heredoc = <<john's wife greeted $people->robert. + END; + +$heredoc = <<bar} + END; + +$heredoc = <<< "END" + some ${beers::softdrink} + END; + +$heredoc = <<< END + {${$object->getName()}} text + END; + +$heredoc = <<<"END" + some {${getName()}} + END; + +$heredoc = <<baz()()} + END; + +$heredoc = <<values[3]->name} text + END; + +$heredoc = <<<"END" + some ${$bar} + END; + +$heredoc = <<bar} text + END; + +$heredoc = <<<"END" + ${foo["${bar}"]} text + END; + +$heredoc = <<{${'a'}}} text + END; + +$heredoc = <<{$baz[1]}} + END; + +$heredoc = <<john's wife greeted $people->robert. + END; + +$heredoc = << + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Tests\Strings; + +use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; + +/** + * Unit test class for the UnnecessaryHeredoc sniff. + * + * @covers \PHP_CodeSniffer\Standards\Generic\Sniffs\Strings\UnnecessaryHeredocSniff + */ +final class UnnecessaryHeredocUnitTest extends AbstractSniffUnitTest +{ + + + /** + * Returns the lines where errors should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of errors that should occur on that line. + * + * @return array + */ + public function getErrorList() + { + return []; + + }//end getErrorList() + + + /** + * Returns the lines where warnings should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of warnings that should occur on that line. + * + * @param string $testFile The name of the file being tested. + * + * @return array + */ + public function getWarningList($testFile='') + { + $warnings = [ + 100 => 1, + 104 => 1, + ]; + + switch ($testFile) { + case 'UnnecessaryHeredocUnitTest.1.inc': + return $warnings; + + case 'UnnecessaryHeredocUnitTest.2.inc': + if (PHP_VERSION_ID >= 70300) { + return $warnings; + } + + // PHP 7.2 or lower: PHP version which doesn't support flexible heredocs/nowdocs yet. + return []; + + default: + return []; + } + + }//end getWarningList() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.1.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.1.inc new file mode 100644 index 00000000..d2ac790d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.1.inc @@ -0,0 +1,34 @@ +'; +$code = '<'.'?php '; + +$string = 'This is a really long string. ' + . 'It is being used for errors. ' + . 'The message is not translated.'; + +$shouldBail = 1 + 1; + +$shouldNotTrigger = 'My' . /* comment */ 'string'; +$shouldNotTrigger = 'My' /* comment */ . 'string'; + +// phpcs:set Generic.Strings.UnnecessaryStringConcat allowMultiline true +$string = 'Multiline strings are allowed ' + . 'when setting is enabled.'; +// phpcs:set Generic.Strings.UnnecessaryStringConcat allowMultiline false + +// phpcs:set Generic.Strings.UnnecessaryStringConcat error false +$throwWarning = 'My' . 'string'; +// phpcs:set Generic.Strings.UnnecessaryStringConcat error true diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.2.inc new file mode 100644 index 00000000..6a5fcba9 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.2.inc @@ -0,0 +1,7 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Tests\WhiteSpace; + +use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; + +/** + * Unit test class for the HereNowdocIdentifierSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\HereNowdocIdentifierSpacingSniff + */ +final class HereNowdocIdentifierSpacingUnitTest extends AbstractSniffUnitTest +{ + + + /** + * Returns the lines where errors should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of errors that should occur on that line. + * + * @return array + */ + public function getErrorList() + { + return [ + 11 => 1, + 15 => 1, + 19 => 1, + 23 => 1, + ]; + + }//end getErrorList() + + + /** + * Returns the lines where warnings should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of warnings that should occur on that line. + * + * @return array + */ + public function getWarningList() + { + return []; + + }//end getWarningList() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.1.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.1.inc new file mode 100644 index 00000000..6c86ac0b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.1.inc @@ -0,0 +1,78 @@ + $a[] = $b; + +class OnlyConstructorPropertyPromotion { + public function __construct( + public string $name = '', + protected $bar + ) {} +} + +class ConstructorPropertyPromotionMixedWithNormalParams { + public function __construct( + public(set) string $name = '', + ?int $optionalParam = 0, + mixed $requiredParam, + ) {} +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.2.inc new file mode 100644 index 00000000..3cfece7a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.2.inc @@ -0,0 +1,7 @@ + + + + + + + Foo.php contents: */ + +class Foo +{ +} + ]]> + + + Foo.php contents: */ + +class MyFoo +{ +} + ]]> + + + + + MyFoo.php contents: */ + +class MyFoo +{ +} + ]]> + + + myFoo.php contents: */ + +class MyFoo +{ +} + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/ValidClassNameStandard.xml b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/ValidClassNameStandard.xml new file mode 100644 index 00000000..cc1a4e9d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/ValidClassNameStandard.xml @@ -0,0 +1,39 @@ + + + + + + + PascalCaseStandard +{ +} + ]]> + + + notPascalCaseStandard +{ +} + ]]> + + + + + PSR7Response +{ +} + ]]> + + + PSR7_Response +{ +} + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/BlockCommentStandard.xml b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/BlockCommentStandard.xml new file mode 100644 index 00000000..0e6a6b85 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/BlockCommentStandard.xml @@ -0,0 +1,280 @@ + + + + + + + /* + A block comment. +*/ + ]]> + + + /** + A block comment. +**/ + ]]> + + + + + /* + * A block comment + * with multiple lines. + */ + ]]> + + + // A block comment +// with multiple lines. + +# A block comment +# with multiple lines. + ]]> + + + + + + + + /* + A block comment. +*/ + ]]> + + + /* A block comment. */ + ]]> + + + + + + + + A block comment. +*/ + ]]> + + + +*/ + ]]> + + + + + + + + A block comment. +*/ + ]]> + + + A block comment. +*/ + ]]> + + + + + + + + A block comment + with multiple lines. + And a second paragraph. +*/ + ]]> + + + A block comment + with + multiple lines. +*/ + ]]> + + + + + + + + * + * A block comment + * with + * multiple lines. + */ + ]]> + + + * with + * multiple lines. +*/ + ]]> + + + + + + + + A block comment. +*/ + ]]> + + + a block comment. +*/ + ]]> + + + + + + + + */ + ]]> + + + */ + ]]> + + + + If asterisks are used, the closer's asterisk should be aligned with these. Otherwise, the closer's asterisk should be aligned with the opener's slash. + + + + * + * A block comment + */ + ]]> + + + */ + ]]> + + + + + /* + A block comment. +*/ + ]]> + + + */ + ]]> + + + + + + + + +echo 'Content'; + ]]> + + + echo 'Content'; + ]]> + + + + + + + + /* + * A block comment + * with + * multiple lines. + */ + ]]> + + + +/* + * A block comment + * with + * multiple lines. + */ + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/PHP/HeredocStandard.xml b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/PHP/HeredocStandard.xml new file mode 100644 index 00000000..b2a63be3 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/PHP/HeredocStandard.xml @@ -0,0 +1,32 @@ + + + + + + + +some text + + + + <<; + +echo <<<'EOD' +some text +EOD; + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceSpaceStandard.xml b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceSpaceStandard.xml new file mode 100644 index 00000000..c0663c2b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceSpaceStandard.xml @@ -0,0 +1,26 @@ + + + + + + + return 42; +} + ]]> + + + + return 42; +} + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc new file mode 100644 index 00000000..beb5ae1a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc @@ -0,0 +1,7 @@ + 0); + +do +{ + echo $i; +} while ($i > 0); + +do +{ + echo $i; +} +while ($i > 0); + +do { echo $i; } while ($i > 0); + +do{ + echo $i; +}while($i > 0); + +while ($i < 1) { + echo $i; +} + +while($i < 1){ + echo $i; +} + +while ($i < 1) { echo $i; } + +for ($i = 1; $i < 1; $i++) { + echo $i; +} + +for($i = 1; $i < 1; $i++){ + echo $i; +} + +for ($i = 1; $i < 1; $i++) { echo $i; } + +if ($i == 0) { + $i = 1; +} + +if($i == 0){ + $i = 1; +} + +if ($i == 0) { $i = 1; } + +if ($i == 0) { + $i = 1; +} else { + $i = 0; +} + +if ($i == 0) { + $i = 1; +}else{ + $i = 0; +} + +if ($i == 0) { $i = 1; } else { $i = 0; } + +if ($i == 0) { + $i = 1; +} else if ($i == 2) { + $i = 0; +} + +if ($i == 0) { + $i = 1; +}else if($i == 2){ + $i = 0; +} + +if ($i == 0) { $i = 1; } else if ($i == 2) { $i = 0; } + +if ($i == 0) { // comments are allowed + $i = 1; +} + +if ($i == 0) {// comments are allowed + $i = 1; +} + +if ($i == 0) { /* comments are allowed*/ + $i = 1; +} + +if ($i == 0) +{ // this is ok + $i = 1; +} + +if ($i == 0) /* this is ok */ { +} + +try { + $code = 'this'; +} catch (Exception $e) { + // Caught! +} + +try { $code = 'this'; } catch (Exception $e) { + // Caught! +} + +do { echo $i; +} while ($i > 0); + +if ($i === 0) { + + $i = 1 +} + +if ($a) { + +} +elseif ($b) { +} + +foreach ($items as $item) { + echo $item; +} + +foreach($items as $item){ + echo $item; +} + +if ($a && $b) // && $c) +{ +} + +if ($a == 5) : + echo "a equals 5"; + echo "..."; +elseif ($a == 6) : + echo "a equals 6"; + echo "!!!"; +else : + echo "a is neither 5 nor 6"; +endif; + +try { + // try body +} +catch (FirstExceptionType $e) { + // catch body +} +catch (OtherExceptionType $e) { + // catch body +} + +switch($foo) { + + case 'bar': + break; + +} + +if ($foo) : +endif; + +?> + +getRow()): ?> +

+ + + +
+ +
+ + + + + + + hello + + + + hello + + + + +getRow()) : ?> +

+ + + + + + + + hello + + + + hello + + 1, +}; + +$r = match($x){1 => 1}; + +// phpcs:set Squiz.ControlStructures.ControlSignature requiredSpacesBeforeColon 2 +if ($a == 5): + echo "a equals 5"; + echo "..."; +elseif ($a == 6) : + echo "a equals 6"; + echo "!!!"; +else : + echo "a is neither 5 nor 6"; +endif; + +// Reset property. +// phpcs:set Squiz.ControlStructures.ControlSignature requiredSpacesBeforeColon 1 diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.1.inc.fixed b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.1.inc.fixed new file mode 100644 index 00000000..03e6bf2c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.1.inc.fixed @@ -0,0 +1,324 @@ + 0); + +do { + echo $i; +} while ($i > 0); + +do { + echo $i; +} while ($i > 0); + +do { +echo $i; } while ($i > 0); + +do { + echo $i; +} while ($i > 0); + +while ($i < 1) { + echo $i; +} + +while ($i < 1) { + echo $i; +} + +while ($i < 1) { +echo $i; } + +for ($i = 1; $i < 1; $i++) { + echo $i; +} + +for ($i = 1; $i < 1; $i++) { + echo $i; +} + +for ($i = 1; $i < 1; $i++) { +echo $i; } + +if ($i == 0) { + $i = 1; +} + +if ($i == 0) { + $i = 1; +} + +if ($i == 0) { +$i = 1; } + +if ($i == 0) { + $i = 1; +} else { + $i = 0; +} + +if ($i == 0) { + $i = 1; +} else { + $i = 0; +} + +if ($i == 0) { +$i = 1; } else { +$i = 0; } + +if ($i == 0) { + $i = 1; +} else if ($i == 2) { + $i = 0; +} + +if ($i == 0) { + $i = 1; +} else if ($i == 2) { + $i = 0; +} + +if ($i == 0) { +$i = 1; } else if ($i == 2) { +$i = 0; } + +if ($i == 0) { // comments are allowed + $i = 1; +} + +if ($i == 0) {// comments are allowed + $i = 1; +} + +if ($i == 0) { /* comments are allowed*/ + $i = 1; +} + +if ($i == 0) { // this is ok + $i = 1; +} + +if ($i == 0) { /* this is ok */ +} + +try { + $code = 'this'; +} catch (Exception $e) { + // Caught! +} + +try { +$code = 'this'; } catch (Exception $e) { + // Caught! +} + +do { +echo $i; +} while ($i > 0); + +if ($i === 0) { + + $i = 1 +} + +if ($a) { + +} elseif ($b) { +} + +foreach ($items as $item) { + echo $item; +} + +foreach ($items as $item) { + echo $item; +} + +if ($a && $b) { // && $c) +} + +if ($a == 5) : + echo "a equals 5"; + echo "..."; +elseif ($a == 6) : + echo "a equals 6"; + echo "!!!"; +else : + echo "a is neither 5 nor 6"; +endif; + +try { + // try body +} catch (FirstExceptionType $e) { + // catch body +} catch (OtherExceptionType $e) { + // catch body +} + +switch ($foo) { + + case 'bar': + break; + +} + +if ($foo) : +endif; + +?> + +getRow()) : ?> +

+ + + +
+ +
+ + + + + + + hello + + + + hello + + + + +getRow()): ?> +

+ + + + + + + + hello + + + + hello + + 1, +}; + +$r = match ($x) { +1 => 1}; + +// phpcs:set Squiz.ControlStructures.ControlSignature requiredSpacesBeforeColon 2 +if ($a == 5) : + echo "a equals 5"; + echo "..."; +elseif ($a == 6) : + echo "a equals 6"; + echo "!!!"; +else : + echo "a is neither 5 nor 6"; +endif; + +// Reset property. +// phpcs:set Squiz.ControlStructures.ControlSignature requiredSpacesBeforeColon 1 diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.2.inc new file mode 100644 index 00000000..ef99b1a2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.2.inc @@ -0,0 +1,5 @@ +words[$wordPos-1]) || $this->words[$wordPos-1] !== ' ') { +} else if ($this->tokens[$pos + 1] === "\n") { +} + +if ($pos === count($this->tokens) - 1) { + $file = '...'.substr($file, (($padding * -1) + 3)); +} + +if (substr($basename, -5) !== 'Sniff') { + $i = ($this->_tokens[$i]['parenthesis_closer'] + 1); +} + +$pos = $this->_getShortCommentEndPos(); +if ($pos === -1) { + $stackPtr = ($tokens[$next][$to] - 1); + $stackPtr = ($tokens[$next][$pattern[$i]['to']] + 1); + $var = (($var1 + $var2) + $var3 + $var4) +} + +$commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); +$commentEnd = ($this->_phpcsFile->findNext(T_DOC_COMMENT, ($commentStart + 1), null, true) - 1); +$expected .= '...'.substr($tokens[($stackPtr - 2)]['content'], -5).$tokens[$stackPtr]['content']; + +if (($tokens[$nextToken - 1]['code']) !== T_WHITESPACE) { + $errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart); +} + +while (($nextSpace = $phpcsFile->findNext(T_WHITESPACE, $nextSpace + 1, $nextBreak)) !== false) { +} + +foreach ($attributes as $id => &$attribute) { +} + +class MyClass +{ + + + public function &myFunction(array &$one, array &$two) + { + + }//end myFunction() + + +}//end class + +if ($index < -1) $index = 0; +if ($index < - 1) $index = 0; + +$three = ceil($one / $two); +$three = ceil(($one / $two) / $four); +$three = ceil($one / ($two / $four)); + +$four = -0.25; + +$three = ceil($one[1] / $two); + +switch ($number % 10) { + case -1: + $suffix = 'st'; + break; +} + +$expectedPermission = array( + 'granted' => 4, + 'denied' => 1, + 'cascade' => TRUE, + 'blockergranted' => 2, + 'blockerdenied' => - 3, + 'effective' => TRUE, + ); + +$value = (int) isset($blah) + 2; +$value = (int) isset($blah) + (int) isset($foo) + (int) isset($bar); + +doSomething(getValue($var, 2)) - $y; + +$codeFiles = array($global => $codeFiles[$global]) + $codeFiles; + +$var = array(-1); +$var = [-1]; +$var = [0, -1, -2]; + +$cntPages = ceil(count($items) / self::ON_PAGE); + +error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING); +error_reporting(E_ALL & ~E_NOTICE | ~E_WARNING); +$results = $stmt->fetchAll(\PDO::FETCH_ASSOC | \PDO::FETCH_GROUP | \PDO::FETCH_UNIQUE); +$di = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS); +foo(1 + 2 + 3); + +if (empty($foo[-1]) === true) { + $foo[-1] = 'foo'; +} + +try { +} catch (AException | BException $e) { +} + +$var = $foo['blah'] + []; + +$a = 2 * ${x} - ${minus}; + +$foo = $bar ?? $baz ?? ''; + +$foo = $myString{-1}; + +$value = (binary) $blah + b"binary $foo"; + +$test = (1 * static::TEST); +$test = myfunc(1 * static::TEST); + +$errorPos = $params[$x]?->getLine() + $commentStart; + +$foo = $this->gmail ?? $this->gmail = new Google_Service_Gmail($this->google); + +exit -1; + +$expr = match ($number - 10) { + -1 => 0, +}; + +$expr = match ($number % 10) { + 1 => 2 * $num, +}; + +$expr = match (true) { + $num * 100 > 500 => 'expression in key', +}; + +// PHP 8.0 named parameters. +if ($pos === count(value: $this->tokens) - 1) { + $file = '...'.substr(string: $file, offset: $padding * -1 + 3); +} + +match ($a) { + 'a' => -1, + 'b', 'c', 'd' => -2, + default => -3, +}; + +$cntPages = ceil(count($items) / parent::ON_PAGE); diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.1.inc.fixed b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.1.inc.fixed new file mode 100644 index 00000000..9fa0216c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.1.inc.fixed @@ -0,0 +1,203 @@ +words[($wordPos-1)]) || $this->words[($wordPos-1)] !== ' ') { +} else if ($this->tokens[($pos + 1)] === "\n") { +} + +if ($pos === (count($this->tokens) - 1)) { + $file = '...'.substr($file, (($padding * -1) + 3)); +} + +if (substr($basename, -5) !== 'Sniff') { + $i = ($this->_tokens[$i]['parenthesis_closer'] + 1); +} + +$pos = $this->_getShortCommentEndPos(); +if ($pos === -1) { + $stackPtr = ($tokens[$next][$to] - 1); + $stackPtr = ($tokens[$next][$pattern[$i]['to']] + 1); + $var = (($var1 + $var2) + $var3 + $var4) +} + +$commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); +$commentEnd = ($this->_phpcsFile->findNext(T_DOC_COMMENT, ($commentStart + 1), null, true) - 1); +$expected .= '...'.substr($tokens[($stackPtr - 2)]['content'], -5).$tokens[$stackPtr]['content']; + +if (($tokens[($nextToken - 1)]['code']) !== T_WHITESPACE) { + $errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart); +} + +while (($nextSpace = $phpcsFile->findNext(T_WHITESPACE, ($nextSpace + 1), $nextBreak)) !== false) { +} + +foreach ($attributes as $id => &$attribute) { +} + +class MyClass +{ + + + public function &myFunction(array &$one, array &$two) + { + + }//end myFunction() + + +}//end class + +if ($index < -1) $index = 0; +if ($index < - 1) $index = 0; + +$three = ceil($one / $two); +$three = ceil(($one / $two) / $four); +$three = ceil($one / ($two / $four)); + +$four = -0.25; + +$three = ceil($one[1] / $two); + +switch ($number % 10) { + case -1: + $suffix = 'st'; + break; +} + +$expectedPermission = array( + 'granted' => 4, + 'denied' => 1, + 'cascade' => TRUE, + 'blockergranted' => 2, + 'blockerdenied' => - 3, + 'effective' => TRUE, + ); + +$value = ((int) isset($blah) + 2); +$value = ((int) isset($blah) + (int) isset($foo) + (int) isset($bar)); + +(doSomething(getValue($var, 2)) - $y); + +$codeFiles = (array($global => $codeFiles[$global]) + $codeFiles); + +$var = array(-1); +$var = [-1]; +$var = [0, -1, -2]; + +$cntPages = ceil(count($items) / self::ON_PAGE); + +error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING); +error_reporting(E_ALL & ~E_NOTICE | ~E_WARNING); +$results = $stmt->fetchAll(\PDO::FETCH_ASSOC | \PDO::FETCH_GROUP | \PDO::FETCH_UNIQUE); +$di = new \RecursiveDirectoryIterator($path, (\RecursiveDirectoryIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS)); +foo(1 + 2 + 3); + +if (empty($foo[-1]) === true) { + $foo[-1] = 'foo'; +} + +try { +} catch (AException | BException $e) { +} + +$var = ($foo['blah'] + []); + +$a = 2 * ${x} - ${minus}; + +$foo = ($bar ?? $baz ?? ''); + +$foo = $myString{-1}; + +$value = ((binary) $blah + b"binary $foo"); + +$test = (1 * static::TEST); +$test = myfunc(1 * static::TEST); + +$errorPos = ($params[$x]?->getLine() + $commentStart); + +$foo = ($this->gmail ?? $this->gmail = new Google_Service_Gmail($this->google)); + +exit -1; + +$expr = match ($number - 10) { + -1 => 0, +}; + +$expr = match ($number % 10) { + 1 => (2 * $num), +}; + +$expr = match (true) { + ($num * 100) > 500 => 'expression in key', +}; + +// PHP 8.0 named parameters. +if ($pos === (count(value: $this->tokens) - 1)) { + $file = '...'.substr(string: $file, offset: ($padding * -1 + 3)); +} + +match ($a) { + 'a' => -1, + 'b', 'c', 'd' => -2, + default => -3, +}; + +$cntPages = ceil(count($items) / parent::ON_PAGE); diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.2.inc new file mode 100644 index 00000000..1284f121 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.2.inc @@ -0,0 +1,7 @@ + $a($b); + +function multipleWhitespaceTokensAfterType(int + + $number) {} + +function spacingBetweenParenthesesShouldBeFixedInOneGo( + + + ) {} + +function newlineAfterReferenceShouldBeFlaggedAndFixed( + & + + $param +) {} + +function newlineAfterReferenceFixerRespectsComment( + & + // comment + $param +) {} + +function newlineAfterVariadicShouldBeFlaggedAndFixed( + ... + + $param +) {} + +function newlineAfterVariadicFixerRespectsComment( + ... + //comment + $param +) {} + +function newlineBeforeAndAfterEqualsSignShouldBeFixedForSpacing0( + $param + + = + + true +) {} + +function commentBeforeOrAfterEqualsSignShouldBeFlaggedNotFixed( + $param /*comment*/ = /*comment*/ true +) {} + +function newlineAndCommentBeforeAndAfterEqualsSignShouldBeFlaggedNotFixed( + $param + + //comment + + = + + //comment + + true +) {} + +// phpcs:set Squiz.Functions.FunctionDeclarationArgumentSpacing equalsSpacing 1 +function newlineBeforeAndAfterEqualsSignShouldBeFixedForSpacing1( + $param + + = + + true +) {} +// phpcs:set Squiz.Functions.FunctionDeclarationArgumentSpacing equalsSpacing 0 + +function newlineBeforeCommaShouldBeFixedInOneGo( + $paramA +, + $paramB + + , + $paramC +) {} + +function newlineBeforeCommaFixerRespectsComments( + $paramA // comment + , + $paramB=10 /* comment */ +, + $paramC=20 # comment + , $paramC=30 + , string $paramC='foo' +) {} + +class PropertyPromotionSpacingAfterComma { + public function __construct(private string|int $propA, protected bool $correctSpace, public MyClass $tooMuchSpace,readonly string $noSpace) {} +} + +class PropertyPromotionSpacingAfterModifier { + public function __construct( + private$noSpace, + public MyClass $tooMuchSpace, + protected readonly string $tooMuchSpaceX2, + readonly + public + string $tooMuchSpaceNewLines, + ) {} +} + +class AsymVisibilityPropertyPromotionSpacingAfterComma { + public function __construct(private(set) string|int $propA, protected(set) bool $correctSpace, public(set) MyClass $tooMuchSpace,public(set) string $noSpace) {} +} + +class AsymVisibilityPropertyPromotionSpacingAfterModifier { + public function __construct( + private(set)$noSpace, + public(set) MyClass $tooMuchSpace, + protected(set) public string $tooMuchSpaceX2, + private + public(set) + string $tooMuchSpaceNewLines, + ) {} +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.1.inc.fixed b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.1.inc.fixed new file mode 100644 index 00000000..356b3742 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.1.inc.fixed @@ -0,0 +1,199 @@ + $a($b); + +function multipleWhitespaceTokensAfterType(int $number) {} + +function spacingBetweenParenthesesShouldBeFixedInOneGo() {} + +function newlineAfterReferenceShouldBeFlaggedAndFixed( + &$param +) {} + +function newlineAfterReferenceFixerRespectsComment( + &// comment + $param +) {} + +function newlineAfterVariadicShouldBeFlaggedAndFixed( + ...$param +) {} + +function newlineAfterVariadicFixerRespectsComment( + ...//comment + $param +) {} + +function newlineBeforeAndAfterEqualsSignShouldBeFixedForSpacing0( + $param=true +) {} + +function commentBeforeOrAfterEqualsSignShouldBeFlaggedNotFixed( + $param /*comment*/ = /*comment*/ true +) {} + +function newlineAndCommentBeforeAndAfterEqualsSignShouldBeFlaggedNotFixed( + $param + + //comment + + = + + //comment + + true +) {} + +// phpcs:set Squiz.Functions.FunctionDeclarationArgumentSpacing equalsSpacing 1 +function newlineBeforeAndAfterEqualsSignShouldBeFixedForSpacing1( + $param = true +) {} +// phpcs:set Squiz.Functions.FunctionDeclarationArgumentSpacing equalsSpacing 0 + +function newlineBeforeCommaShouldBeFixedInOneGo( + $paramA, + $paramB, + $paramC +) {} + +function newlineBeforeCommaFixerRespectsComments( + $paramA, // comment + $paramB=10, /* comment */ + $paramC=20, # comment + $paramC=30, + string $paramC='foo' +) {} + +class PropertyPromotionSpacingAfterComma { + public function __construct(private string|int $propA, protected bool $correctSpace, public MyClass $tooMuchSpace, readonly string $noSpace) {} +} + +class PropertyPromotionSpacingAfterModifier { + public function __construct( + private $noSpace, + public MyClass $tooMuchSpace, + protected readonly string $tooMuchSpaceX2, + readonly public string $tooMuchSpaceNewLines, + ) {} +} + +class AsymVisibilityPropertyPromotionSpacingAfterComma { + public function __construct(private(set) string|int $propA, protected(set) bool $correctSpace, public(set) MyClass $tooMuchSpace, public(set) string $noSpace) {} +} + +class AsymVisibilityPropertyPromotionSpacingAfterModifier { + public function __construct( + private(set) $noSpace, + public(set) MyClass $tooMuchSpace, + protected(set) public string $tooMuchSpaceX2, + private public(set) string $tooMuchSpaceNewLines, + ) {} +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.2.inc new file mode 100644 index 00000000..1b572336 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.2.inc @@ -0,0 +1,6 @@ +fetch(PDO::FETCH_NUM)) { + $result[$row[0]] = array(); + $result[$row[0]][] = $current; + + self::$_inTransaction = TRUE; + parent::$_inTransaction = TRUE; + static::$_inTransaction = TRUE; + $$varName = $varValue; + } + +}//end getVar() + +class myClass +{ + private static $_dbh = NULL; + public $dbh = NULL; + protected $dbh = NULL; + var $dbh = NULL; // Old PHP4 compatible code. +} + +A::$a = 'b'; +\A::$a = 'c'; +\A\B\C::$d = 'd'; +B\C::$d = 'e'; + +@$a = 1; + +$a = []; +foreach ($a as $b) + $c = 'd'; + +$var = $var2; +list ($a, $b) = explode(',', $c); +$var1 ? $var2 = 0 : $var2 = 1; + +$obj->$classVar = $prefix.'-'.$type; + +$closureWithDefaultParamter = function(array $testArray=array()) {}; +?> + + + 10, + false => 0 + }, +]; + +$arrow_function = fn ($a = null) => $a; + +function ($html) { + $regEx = '/regexp/'; + + return preg_replace_callback($regEx, function ($matches) { + [$all] = $matches; + return $all; + }, $html); +}; + + +function () { + $a = false; + + some_label: + + $b = getB(); +}; + +?> + + +// Issue PHPCSStandards/PHP_CodeSniffer#537. + + + + + + + + + + + + +field = $result; +$filtered_results->$field = $result; +$filtered_results->$row->field = $result; +$filtered_results->$row->$field = $result; + +$filtered_results[ $i ]->field = $result; +$filtered_results[ $i ]->$field = $result; +$filtered_results[ $i ]->$row->field = $result; +$filtered_results[ $i ]->$row->$field = $result; +$filtered_results[ $i ]->$row[0]->field = $result; +$filtered_results[ $i ]->$row[$j]->$field = $result; diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.2.inc new file mode 100644 index 00000000..3befd507 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.2.inc @@ -0,0 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 'a', 'b' => 'b' ), + $varQ = 'string', + $varR = 123; +} + +// Make sure the determination of whether a property is the first property or not is done correctly. +class ClassUsingSimpleTraits +{ + use HelloWorld; + + + /* comment */ + public $firstVar = array( 'a', 'b' ); + protected $secondVar = true; +} + +class ClassUsingComplexTraits +{ + use A, B { + B::smallTalk insteadof A; + A::bigTalk insteadof B; + } + + + + public $firstVar = array( 'a', 'b' ); + + + /* comment */ + protected $secondVar = true; +} + +class Foo +{ + + + private function foo() + { + } + + + /* no error here because after function */ + private $bar = false; +} + +class CommentedOutCodeAtStartOfClass { + + /** + * Description. + * + * @var bool + */ + //public $commented_out_property = true; + + /** + * Description. + * + * @var bool + */ + public $property = true; +} + +class CommentedOutCodeAtStartOfClassNoBlankLine { + + // phpcs:disable Stnd.Cat.Sniff -- For reasons. + /** + * Description. + * + * @var bool + */ + public $property = true; +} + +class HasAttributes +{ + /** + * Short description of the member variable. + * + * @var array + */ + + #[ORM\Id]#[ORM\Column("integer")] + + private $id; + + + /** + * Short description of the member variable. + * + * @var array + */ + #[ORM\GeneratedValue] + + #[ORM\Column(ORM\Column::T_INTEGER)] + protected $height; + + #[SingleAttribute] + protected $propertySingle; + + #[FirstAttribute] + #[SecondAttribute] + protected $propertyDouble; + #[ThirdAttribute] + protected $propertyWithoutSpacing; +} + +enum SomeEnum +{ + // Enum cannot have properties + + case ONE = 'one'; +} + +class SupportReadonlyProperties { + readonly int $readonlyA; + public readonly string $publicReadonly; + readonly bool $readonlyB; + readonly private bool $readonlyPrivate; +} + +class NoPreambleMultilineDeclaration { + public + static + int $prop = 1; +} + +class MultipleBlankLinesInPreAmble { + + /** + * Docblock. + */ + + #[MyAttribute] + + + #[ + + BlankLinesWithinAnAttributeShouldBeLeftAlone + + ] + + public $prop; +} + +final class BlankLinesBetweenVsAttributesWithoutCommentIssueSquiz3594 +{ + + // PHPCS can fix blank lines for the first property, but not for the second. (fixed now) + #[SingleAttribute] + + public $property1; + #[SingleAttribute] + + public $property2; +} + +class PHP84FinalProperties { + final int $finalA; + + /** + * Docblock + */ + public final string $publicfinal; + #[AnAttribute] + final bool $finalB; + + final private bool $finalPrivate; +} + +class MultilineCommentShouldNotBeSplitUp { + // This is the first line + // of a multi-line comment + // which should be recognized as belonging + // with the property. + public $prop; + + + /* This is the first line + of a multi-line comment + which should be recognized as belonging + with the property. + */ + public $prop; +} + +class AsymVisibility { + protected private(set) int $asymProtectedPrivate; + + /** + * Docblock + */ + protected(set) final string $asymProtected; + #[AnAttribute] + + public(set) string|bool $asymPublic; + + + private(set) private bool $asymPrivate; +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc.fixed b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc.fixed new file mode 100644 index 00000000..d87c8b74 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc.fixed @@ -0,0 +1,448 @@ + 'a', 'b' => 'b' ), + $varQ = 'string', + $varR = 123; +} + +// Make sure the determination of whether a property is the first property or not is done correctly. +class ClassUsingSimpleTraits +{ + use HelloWorld; + + /* comment */ + public $firstVar = array( 'a', 'b' ); + + protected $secondVar = true; +} + +class ClassUsingComplexTraits +{ + use A, B { + B::smallTalk insteadof A; + A::bigTalk insteadof B; + } + + public $firstVar = array( 'a', 'b' ); + + /* comment */ + protected $secondVar = true; +} + +class Foo +{ + + + private function foo() + { + } + + + /* no error here because after function */ + private $bar = false; +} + +class CommentedOutCodeAtStartOfClass { + + /** + * Description. + * + * @var bool + */ + //public $commented_out_property = true; + + /** + * Description. + * + * @var bool + */ + public $property = true; +} + +class CommentedOutCodeAtStartOfClassNoBlankLine { + + // phpcs:disable Stnd.Cat.Sniff -- For reasons. + + /** + * Description. + * + * @var bool + */ + public $property = true; +} + +class HasAttributes +{ + + /** + * Short description of the member variable. + * + * @var array + */ + #[ORM\Id]#[ORM\Column("integer")] + private $id; + + /** + * Short description of the member variable. + * + * @var array + */ + #[ORM\GeneratedValue] + #[ORM\Column(ORM\Column::T_INTEGER)] + protected $height; + + #[SingleAttribute] + protected $propertySingle; + + #[FirstAttribute] + #[SecondAttribute] + protected $propertyDouble; + + #[ThirdAttribute] + protected $propertyWithoutSpacing; +} + +enum SomeEnum +{ + // Enum cannot have properties + + case ONE = 'one'; +} + +class SupportReadonlyProperties { + + readonly int $readonlyA; + + public readonly string $publicReadonly; + + readonly bool $readonlyB; + + readonly private bool $readonlyPrivate; +} + +class NoPreambleMultilineDeclaration { + + public + static + int $prop = 1; +} + +class MultipleBlankLinesInPreAmble { + + /** + * Docblock. + */ + #[MyAttribute] + #[ + + BlankLinesWithinAnAttributeShouldBeLeftAlone + + ] + public $prop; +} + +final class BlankLinesBetweenVsAttributesWithoutCommentIssueSquiz3594 +{ + + // PHPCS can fix blank lines for the first property, but not for the second. (fixed now) + #[SingleAttribute] + public $property1; + + #[SingleAttribute] + public $property2; +} + +class PHP84FinalProperties { + + final int $finalA; + + /** + * Docblock + */ + public final string $publicfinal; + + #[AnAttribute] + final bool $finalB; + + final private bool $finalPrivate; +} + +class MultilineCommentShouldNotBeSplitUp { + + // This is the first line + // of a multi-line comment + // which should be recognized as belonging + // with the property. + public $prop; + + /* This is the first line + of a multi-line comment + which should be recognized as belonging + with the property. + */ + public $prop; +} + +class AsymVisibility { + + protected private(set) int $asymProtectedPrivate; + + /** + * Docblock + */ + protected(set) final string $asymProtected; + + #[AnAttribute] + public(set) string|bool $asymPublic; + + private(set) private bool $asymPrivate; +} diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.2.inc b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.2.inc new file mode 100644 index 00000000..2aab7c05 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.2.inc @@ -0,0 +1,10 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Util; + +use InvalidArgumentException; +use PHP_CodeSniffer\Exceptions\RuntimeException; + +final class MessageCollector +{ + + /** + * Indicator for a (blocking) error. + * + * @var int + */ + const ERROR = 1; + + /** + * Indicator for a warning. + * + * @var int + */ + const WARNING = 2; + + /** + * Indicator for a notice. + * + * @var int + */ + const NOTICE = 4; + + /** + * Indicator for a deprecation notice. + * + * @var int + */ + const DEPRECATED = 8; + + /** + * Indicator for ordering the messages based on severity first, order received second. + * + * @var string + */ + const ORDERBY_SEVERITY = 'severity'; + + /** + * Indicator for ordering the messages based on the order in which they were received. + * + * @var string + */ + const ORDERBY_RECEIVED = 'received'; + + /** + * Collected messages. + * + * @var array> The value for each array entry is an associative array + * which holds two keys: + * - 'message' string The message text. + * - 'type' int The type of the message based on the + * above declared error level constants. + */ + private $cache = []; + + + /** + * Add a new message. + * + * @param string $message The message text. + * @param int $type The type of message. Should be one of the following constants: + * MessageCollector::ERROR, MessageCollector::WARNING, MessageCollector::NOTICE + * or MessageCollector::DEPRECATED. + * Defaults to MessageCollector::NOTICE. + * + * @return void + * + * @throws \InvalidArgumentException If the message text is not a string. + * @throws \InvalidArgumentException If the message type is not one of the accepted types. + */ + public function add($message, $type=self::NOTICE) + { + if (is_string($message) === false) { + throw new InvalidArgumentException('The $message should be of type string. Received: '.gettype($message).'.'); + } + + if ($type !== self::ERROR + && $type !== self::WARNING + && $type !== self::NOTICE + && $type !== self::DEPRECATED + ) { + throw new InvalidArgumentException('The message $type should be one of the predefined MessageCollector constants. Received: '.$type.'.'); + } + + $this->cache[] = [ + 'message' => $message, + 'type' => $type, + ]; + + }//end add() + + + /** + * Determine whether or not the currently cached errors include blocking errors. + * + * @return bool + */ + public function containsBlockingErrors() + { + $seenTypes = $this->arrayColumn($this->cache, 'type'); + $typeFrequency = array_count_values($seenTypes); + return isset($typeFrequency[self::ERROR]); + + }//end containsBlockingErrors() + + + /** + * Display the cached messages. + * + * Displaying the messages will also clear the message cache. + * + * @param string $order Optional. The order in which to display the messages. + * Should be one of the following constants: MessageCollector::ORDERBY_SEVERITY, + * MessageCollector::ORDERBY_RECEIVED. + * Defaults to MessageCollector::ORDERBY_SEVERITY. + * + * @return void + * + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException When there are blocking errors. + */ + public function display($order=self::ORDERBY_SEVERITY) + { + if ($this->cache === []) { + return; + } + + $blocking = $this->containsBlockingErrors(); + $messageInfo = $this->prefixAll($this->cache); + $this->clearCache(); + + if ($order === self::ORDERBY_RECEIVED) { + $messages = $this->arrayColumn($messageInfo, 'message'); + } else { + $messages = $this->sortBySeverity($messageInfo); + } + + $allMessages = implode(PHP_EOL, $messages).PHP_EOL.PHP_EOL; + + if ($blocking === true) { + throw new RuntimeException($allMessages); + } else { + echo $allMessages; + } + + }//end display() + + + /** + * Label all messages based on their type. + * + * @param array> $messages A multi-dimensional array of messages with their severity. + * + * @return array> + */ + private function prefixAll(array $messages) + { + foreach ($messages as $i => $details) { + $messages[$i]['message'] = $this->prefix($details['message'], $details['type']); + } + + return $messages; + + }//end prefixAll() + + + /** + * Add a message type prefix to a message. + * + * @param string $message The message text. + * @param int $type The type of message. + * + * @return string + */ + private function prefix($message, $type) + { + switch ($type) { + case self::ERROR: + $message = 'ERROR: '.$message; + break; + + case self::WARNING: + $message = 'WARNING: '.$message; + break; + + case self::DEPRECATED: + $message = 'DEPRECATED: '.$message; + break; + + default: + $message = 'NOTICE: '.$message; + break; + } + + return $message; + + }//end prefix() + + + /** + * Sort an array of messages by severity. + * + * @param array> $messages A multi-dimensional array of messages with their severity. + * + * @return array A single dimensional array of only messages, sorted by severity. + */ + private function sortBySeverity(array $messages) + { + if (count($messages) === 1) { + return [$messages[0]['message']]; + } + + $errors = []; + $warnings = []; + $notices = []; + $deprecations = []; + + foreach ($messages as $details) { + switch ($details['type']) { + case self::ERROR: + $errors[] = $details['message']; + break; + + case self::WARNING: + $warnings[] = $details['message']; + break; + + case self::DEPRECATED: + $deprecations[] = $details['message']; + break; + + default: + $notices[] = $details['message']; + break; + } + } + + return array_merge($errors, $warnings, $notices, $deprecations); + + }//end sortBySeverity() + + + /** + * Clear the message cache. + * + * @return void + */ + private function clearCache() + { + $this->cache = []; + + }//end clearCache() + + + /** + * Return the values from a single column in the input array. + * + * Polyfill for the PHP 5.5+ native array_column() function (for the functionality needed here). + * + * @param array> $input A multi-dimensional array from which to pull a column of values. + * @param string $columnKey The name of the column of values to return. + * + * @link https://www.php.net/function.array-column + * + * @return array + */ + private function arrayColumn(array $input, $columnKey) + { + if (function_exists('array_column') === true) { + // PHP 5.5+. + return array_column($input, $columnKey); + } + + // PHP 5.4. + $callback = function ($row) use ($columnKey) { + return $row[$columnKey]; + }; + + return array_map($callback, $input); + + }//end arrayColumn() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Config/AbstractRealConfigTestCase.php b/vendor/squizlabs/php_codesniffer/tests/Core/Config/AbstractRealConfigTestCase.php new file mode 100644 index 00000000..6f5cd884 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Config/AbstractRealConfigTestCase.php @@ -0,0 +1,92 @@ +setAccessible(true); + $property->setValue(null, $value); + $property->setAccessible(false); + + }//end setStaticConfigProperty() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Config/ExtensionsArgTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Config/ExtensionsArgTest.php new file mode 100644 index 00000000..e63b1fef --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Config/ExtensionsArgTest.php @@ -0,0 +1,128 @@ +assertSame($expected, $config->extensions); + + }//end testValidExtensions() + + + /** + * Data provider. + * + * @see self::testValidExtensions() + * + * @return array>> + */ + public static function dataValidExtensions() + { + return [ + // Passing an empty extensions list is not useful, as it will result in no files being scanned, + // but that's the responsibility of the user. + 'Empty extensions list' => [ + 'passedValue' => '', + 'expected' => [], + ], + 'Single extension passed: php' => [ + 'passedValue' => 'php', + 'expected' => [ + 'php' => 'PHP', + ], + ], + // This would cause PHPCS to scan python files as PHP, which will probably cause very weird scan results, + // but that's the responsibility of the user. + 'Single extension passed: py' => [ + 'passedValue' => 'py', + 'expected' => [ + 'py' => 'PHP', + ], + ], + // This would likely result in a problem when PHPCS can't find a "PY" tokenizer class, + // but that's not our concern at this moment. Support for non-PHP tokenizers is being dropped soon anyway. + 'Single extension passed with language: py/py' => [ + 'passedValue' => 'py/py', + 'expected' => [ + 'py' => 'PY', + ], + ], + 'Multiple extensions passed: php,js,css' => [ + 'passedValue' => 'php,js,css', + 'expected' => [ + 'php' => 'PHP', + 'js' => 'JS', + 'css' => 'CSS', + ], + ], + 'Multiple extensions passed, some with language: php,inc/php,phpt/php,js' => [ + 'passedValue' => 'php,inc/php,phpt/php,js', + 'expected' => [ + 'php' => 'PHP', + 'inc' => 'PHP', + 'phpt' => 'PHP', + 'js' => 'JS', + ], + ], + 'File extensions are set case sensitively (and filtering is case sensitive too)' => [ + 'passedValue' => 'PHP,php', + 'expected' => [ + 'PHP' => 'PHP', + 'php' => 'PHP', + ], + ], + ]; + + }//end dataValidExtensions() + + + /** + * Ensure that only the first argument is processed and others are ignored. + * + * @return void + */ + public function testOnlySetOnce() + { + $config = new ConfigDouble( + [ + '--extensions=php', + '--extensions=inc,module', + ] + ); + + $this->assertSame(['php' => 'PHP'], $config->extensions); + + }//end testOnlySetOnce() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Config/GeneratorArgTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Config/GeneratorArgTest.php new file mode 100644 index 00000000..12fe1c66 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Config/GeneratorArgTest.php @@ -0,0 +1,163 @@ +markTestSkipped('The `--generator` CLI flag is only supported for the `phpcs` command'); + } + + }//end maybeSkipTests() + + + /** + * Ensure that the generator property is set when the parameter is passed a valid value. + * + * @param string $argumentValue Generator name passed on the command line. + * @param string $expectedPropertyValue Expected value of the generator property. + * + * @dataProvider dataValidGeneratorNames + * + * @return void + */ + public function testValidGenerators($argumentValue, $expectedPropertyValue) + { + $config = new ConfigDouble(["--generator=$argumentValue"]); + + $this->assertSame($expectedPropertyValue, $config->generator); + + }//end testValidGenerators() + + + /** + * Data provider for testValidGenerators(). + * + * @see self::testValidGenerators() + * + * @return array> + */ + public static function dataValidGeneratorNames() + { + return [ + 'Text generator passed' => [ + 'argumentValue' => 'Text', + 'expectedPropertyValue' => 'Text', + ], + 'HTML generator passed' => [ + 'argumentValue' => 'HTML', + 'expectedPropertyValue' => 'HTML', + ], + 'Markdown generator passed' => [ + 'argumentValue' => 'Markdown', + 'expectedPropertyValue' => 'Markdown', + ], + 'Uppercase Text generator passed' => [ + 'argumentValue' => 'TEXT', + 'expectedPropertyValue' => 'Text', + ], + 'Mixed case Text generator passed' => [ + 'argumentValue' => 'tEXt', + 'expectedPropertyValue' => 'Text', + ], + 'Lowercase HTML generator passed' => [ + 'argumentValue' => 'html', + 'expectedPropertyValue' => 'HTML', + ], + ]; + + }//end dataValidGeneratorNames() + + + /** + * Ensure that only the first argument is processed and others are ignored. + * + * @return void + */ + public function testOnlySetOnce() + { + $config = new ConfigDouble( + [ + '--generator=Text', + '--generator=HTML', + '--generator=InvalidGenerator', + ] + ); + + $this->assertSame('Text', $config->generator); + + }//end testOnlySetOnce() + + + /** + * Ensure that an exception is thrown for an invalid generator. + * + * @param string $generatorName Generator name. + * + * @dataProvider dataInvalidGeneratorNames + * + * @return void + */ + public function testInvalidGenerator($generatorName) + { + $exception = 'PHP_CodeSniffer\Exceptions\DeepExitException'; + $message = 'ERROR: "'.$generatorName.'" is not a valid generator. The following generators are supported: Text, HTML and Markdown.'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + new ConfigDouble(["--generator={$generatorName}"]); + + }//end testInvalidGenerator() + + + /** + * Data provider for testInvalidGenerator(). + * + * @see self::testInvalidGenerator() + * + * @return array> + */ + public static function dataInvalidGeneratorNames() + { + return [ + ['InvalidGenerator'], + ['Text,HTML'], + [''], + ]; + + }//end dataInvalidGeneratorNames() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportArgsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportArgsTest.php new file mode 100644 index 00000000..60b5a7c4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportArgsTest.php @@ -0,0 +1,64 @@ +markTestSkipped('This test needs CS mode to run'); + } + + $config = new ConfigDouble(['--report-file='.__DIR__.'/report.txt']); + + $this->assertTrue(is_string($config->reportFile)); + $this->assertStringEndsWith('/report.txt', $config->reportFile); + $this->assertSame(['full' => null], $config->reports); + + }//end testReportFileDoesNotSetReportsCs() + + + /** + * [CBF mode] Verify that passing `--report-file` does not influence *which* reports get activated. + * + * @group CBF + * + * @return void + */ + public function testReportFileDoesNotSetReportsCbf() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $config = new ConfigDouble(['--report-file='.__DIR__.'/report.txt']); + + $this->assertNull($config->reportFile); + $this->assertSame(['full' => null], $config->reports); + + }//end testReportFileDoesNotSetReportsCbf() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.inc new file mode 100644 index 00000000..83516798 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.inc @@ -0,0 +1,105 @@ + fn() => return 1, + 'b' => fn() => return 1, +]; + +/* testStaticArrowFunction */ +static fn ($a) => $a; + +return 0; + +/* testArrowFunctionReturnValue */ +fn(): array => [a($a, $b)]; + +/* testArrowFunctionAsArgument */ +$foo = foo( + fn() => bar() +); + +/* testArrowFunctionWithArrayAsArgument */ +$foo = foo( + fn() => [$row[0], $row[3]] +); + +$match = match ($a) { + /* testMatchCase */ + 1 => 'foo', + /* testMatchDefault */ + default => 'bar' +}; + +$match = match ($a) { + /* testMatchMultipleCase */ + 1, 2, => $a * $b, + /* testMatchDefaultComma */ + default, => 'something' +}; + +match ($pressedKey) { + /* testMatchFunctionCall */ + Key::RETURN_ => save($value, $user) +}; + +$result = match (true) { + /* testMatchFunctionCallArm */ + str_contains($text, 'Welcome') || str_contains($text, 'Hello') => 'en', + str_contains($text, 'Bienvenue') || str_contains($text, 'Bonjour') => 'fr', + default => 'pl' +}; + +/* testMatchClosure */ +$result = match ($key) { + 1 => function($a, $b) {}, + 2 => function($b, $c) {}, +}; + +/* testMatchArray */ +$result = match ($key) { + 1 => [1,2,3], + 2 => [1 => one(), 2 => two()], +}; + +/* testNestedMatch */ +$result = match ($key) { + 1 => match ($key) { + 1 => 'one', + 2 => 'two', + }, + 2 => match ($key) { + 1 => 'two', + 2 => 'one', + }, +}; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.php new file mode 100644 index 00000000..ba62360a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.php @@ -0,0 +1,457 @@ + + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::findEndOfStatement method. + * + * @covers \PHP_CodeSniffer\Files\File::findEndOfStatement + */ +final class FindEndOfStatementTest extends AbstractMethodUnitTest +{ + + + /** + * Test that end of statement is NEVER before the "current" token. + * + * @return void + */ + public function testEndIsNeverLessThanCurrentToken() + { + $tokens = self::$phpcsFile->getTokens(); + $errors = []; + + for ($i = 0; $i < self::$phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + $end = self::$phpcsFile->findEndOfStatement($i); + + // Collect all the errors. + if ($end < $i) { + $errors[] = sprintf( + 'End of statement for token %1$d (%2$s: %3$s) on line %4$d is %5$d (%6$s), which is less than %1$d', + $i, + $tokens[$i]['type'], + $tokens[$i]['content'], + $tokens[$i]['line'], + $end, + $tokens[$end]['type'] + ); + } + } + + $this->assertSame([], $errors); + + }//end testEndIsNeverLessThanCurrentToken() + + + /** + * Test a simple assignment. + * + * @return void + */ + public function testSimpleAssignment() + { + $start = $this->getTargetToken('/* testSimpleAssignment */', T_VARIABLE); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 5), $found); + + }//end testSimpleAssignment() + + + /** + * Test a direct call to a control structure. + * + * @return void + */ + public function testControlStructure() + { + $start = $this->getTargetToken('/* testControlStructure */', T_WHILE); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 6), $found); + + }//end testControlStructure() + + + /** + * Test the assignment of a closure. + * + * @return void + */ + public function testClosureAssignment() + { + $start = $this->getTargetToken('/* testClosureAssignment */', T_VARIABLE, '$a'); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 13), $found); + + }//end testClosureAssignment() + + + /** + * Test using a heredoc in a function argument. + * + * @return void + */ + public function testHeredocFunctionArg() + { + // Find the end of the function. + $start = $this->getTargetToken('/* testHeredocFunctionArg */', T_STRING, 'myFunction'); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 10), $found); + + // Find the end of the heredoc. + $start += 2; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 4), $found); + + // Find the end of the last arg. + $start = ($found + 2); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame($start, $found); + + }//end testHeredocFunctionArg() + + + /** + * Test parts of a switch statement. + * + * @return void + */ + public function testSwitch() + { + // Find the end of the switch. + $start = $this->getTargetToken('/* testSwitch */', T_SWITCH); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 28), $found); + + // Find the end of the case. + $start += 9; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 8), $found); + + // Find the end of default case. + $start += 11; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 6), $found); + + }//end testSwitch() + + + /** + * Test statements that are array values. + * + * @return void + */ + public function testStatementAsArrayValue() + { + // Test short array syntax. + $start = $this->getTargetToken('/* testStatementAsArrayValue */', T_NEW); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 2), $found); + + // Test long array syntax. + $start += 12; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 2), $found); + + // Test same statement outside of array. + $start += 10; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 3), $found); + + }//end testStatementAsArrayValue() + + + /** + * Test a use group. + * + * @return void + */ + public function testUseGroup() + { + $start = $this->getTargetToken('/* testUseGroup */', T_USE); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 23), $found); + + }//end testUseGroup() + + + /** + * Test arrow function as array value. + * + * @return void + */ + public function testArrowFunctionArrayValue() + { + $start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_FN); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 9), $found); + + }//end testArrowFunctionArrayValue() + + + /** + * Test static arrow function. + * + * @return void + */ + public function testStaticArrowFunction() + { + $static = $this->getTargetToken('/* testStaticArrowFunction */', T_STATIC); + $fn = $this->getTargetToken('/* testStaticArrowFunction */', T_FN); + + $endOfStatementStatic = self::$phpcsFile->findEndOfStatement($static); + $endOfStatementFn = self::$phpcsFile->findEndOfStatement($fn); + + $this->assertSame($endOfStatementFn, $endOfStatementStatic); + + }//end testStaticArrowFunction() + + + /** + * Test arrow function with return value. + * + * @return void + */ + public function testArrowFunctionReturnValue() + { + $start = $this->getTargetToken('/* testArrowFunctionReturnValue */', T_FN); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 18), $found); + + }//end testArrowFunctionReturnValue() + + + /** + * Test arrow function used as a function argument. + * + * @return void + */ + public function testArrowFunctionAsArgument() + { + $start = $this->getTargetToken('/* testArrowFunctionAsArgument */', T_FN); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 8), $found); + + }//end testArrowFunctionAsArgument() + + + /** + * Test arrow function with arrays used as a function argument. + * + * @return void + */ + public function testArrowFunctionWithArrayAsArgument() + { + $start = $this->getTargetToken('/* testArrowFunctionWithArrayAsArgument */', T_FN); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 17), $found); + + }//end testArrowFunctionWithArrayAsArgument() + + + /** + * Test simple match expression case. + * + * @return void + */ + public function testMatchCase() + { + $start = $this->getTargetToken('/* testMatchCase */', T_LNUMBER); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 5), $found); + + $start = $this->getTargetToken('/* testMatchCase */', T_CONSTANT_ENCAPSED_STRING); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 1), $found); + + }//end testMatchCase() + + + /** + * Test simple match expression default case. + * + * @return void + */ + public function testMatchDefault() + { + $start = $this->getTargetToken('/* testMatchDefault */', T_MATCH_DEFAULT); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 4), $found); + + $start = $this->getTargetToken('/* testMatchDefault */', T_CONSTANT_ENCAPSED_STRING); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame($start, $found); + + }//end testMatchDefault() + + + /** + * Test multiple comma-separated match expression case values. + * + * @return void + */ + public function testMatchMultipleCase() + { + $start = $this->getTargetToken('/* testMatchMultipleCase */', T_LNUMBER); + $found = self::$phpcsFile->findEndOfStatement($start); + $this->assertSame(($start + 13), $found); + + $start += 6; + $found = self::$phpcsFile->findEndOfStatement($start); + $this->assertSame(($start + 7), $found); + + }//end testMatchMultipleCase() + + + /** + * Test match expression default case with trailing comma. + * + * @return void + */ + public function testMatchDefaultComma() + { + $start = $this->getTargetToken('/* testMatchDefaultComma */', T_MATCH_DEFAULT); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 5), $found); + + }//end testMatchDefaultComma() + + + /** + * Test match expression with function call. + * + * @return void + */ + public function testMatchFunctionCall() + { + $start = $this->getTargetToken('/* testMatchFunctionCall */', T_STRING); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 12), $found); + + $start += 8; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 1), $found); + + }//end testMatchFunctionCall() + + + /** + * Test match expression with function call in the arm. + * + * @return void + */ + public function testMatchFunctionCallArm() + { + // Check the first case. + $start = $this->getTargetToken('/* testMatchFunctionCallArm */', T_STRING); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 21), $found); + + // Check the second case. + $start += 24; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 21), $found); + + }//end testMatchFunctionCallArm() + + + /** + * Test match expression with closure. + * + * @return void + */ + public function testMatchClosure() + { + $start = $this->getTargetToken('/* testMatchClosure */', T_LNUMBER); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 14), $found); + + $start += 17; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 14), $found); + + }//end testMatchClosure() + + + /** + * Test match expression with array declaration. + * + * @return void + */ + public function testMatchArray() + { + $start = $this->getTargetToken('/* testMatchArray */', T_LNUMBER); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 11), $found); + + $start += 14; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 22), $found); + + }//end testMatchArray() + + + /** + * Test nested match expressions. + * + * @return void + */ + public function testNestedMatch() + { + $start = $this->getTargetToken('/* testNestedMatch */', T_LNUMBER); + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 30), $found); + + $start += 21; + $found = self::$phpcsFile->findEndOfStatement($start); + + $this->assertSame(($start + 5), $found); + + }//end testNestedMatch() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindExtendedClassNameTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindExtendedClassNameTest.inc new file mode 100644 index 00000000..dae2cd96 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindExtendedClassNameTest.inc @@ -0,0 +1,52 @@ + + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::findExtendedClassName method. + * + * @covers \PHP_CodeSniffer\Files\File::findExtendedClassName + */ +final class FindExtendedClassNameTest extends AbstractMethodUnitTest +{ + + + /** + * Test getting a `false` result when a non-existent token is passed. + * + * @return void + */ + public function testNonExistentToken() + { + $result = self::$phpcsFile->findExtendedClassName(100000); + $this->assertFalse($result); + + }//end testNonExistentToken() + + + /** + * Test getting a `false` result when a token other than one of the supported tokens is passed. + * + * @return void + */ + public function testNotAClass() + { + $token = $this->getTargetToken('/* testNotAClass */', [T_FUNCTION]); + $result = self::$phpcsFile->findExtendedClassName($token); + $this->assertFalse($result); + + }//end testNotAClass() + + + /** + * Test retrieving the name of the class being extended by another class + * (or interface). + * + * @param string $identifier Comment which precedes the test case. + * @param string|false $expected Expected function output. + * + * @dataProvider dataExtendedClass + * + * @return void + */ + public function testFindExtendedClassName($identifier, $expected) + { + $OOToken = $this->getTargetToken($identifier, [T_CLASS, T_ANON_CLASS, T_INTERFACE]); + $result = self::$phpcsFile->findExtendedClassName($OOToken); + $this->assertSame($expected, $result); + + }//end testFindExtendedClassName() + + + /** + * Data provider for the FindExtendedClassName test. + * + * @see testFindExtendedClassName() + * + * @return array> + */ + public static function dataExtendedClass() + { + return [ + 'class does not extend' => [ + 'identifier' => '/* testNonExtendedClass */', + 'expected' => false, + ], + 'class extends unqualified class' => [ + 'identifier' => '/* testExtendsUnqualifiedClass */', + 'expected' => 'testFECNClass', + ], + 'class extends fully qualified class' => [ + 'identifier' => '/* testExtendsFullyQualifiedClass */', + 'expected' => '\PHP_CodeSniffer\Tests\Core\File\testFECNClass', + ], + 'class extends partially qualified class' => [ + 'identifier' => '/* testExtendsPartiallyQualifiedClass */', + 'expected' => 'Core\File\RelativeClass', + ], + 'interface does not extend' => [ + 'identifier' => '/* testNonExtendedInterface */', + 'expected' => false, + ], + 'interface extends unqualified interface' => [ + 'identifier' => '/* testInterfaceExtendsUnqualifiedInterface */', + 'expected' => 'testFECNInterface', + ], + 'interface extends fully qualified interface' => [ + 'identifier' => '/* testInterfaceExtendsFullyQualifiedInterface */', + 'expected' => '\PHP_CodeSniffer\Tests\Core\File\testFECNInterface', + ], + 'anon class extends unqualified class' => [ + 'identifier' => '/* testExtendedAnonClass */', + 'expected' => 'testFECNExtendedAnonClass', + ], + 'class does not extend but contains anon class which extends' => [ + 'identifier' => '/* testNestedExtendedClass */', + 'expected' => false, + ], + 'anon class extends, nested in non-extended class' => [ + 'identifier' => '/* testNestedExtendedAnonClass */', + 'expected' => 'testFECNAnonClass', + ], + 'class extends and implements' => [ + 'identifier' => '/* testClassThatExtendsAndImplements */', + 'expected' => 'testFECNClass', + ], + 'class implements and extends' => [ + 'identifier' => '/* testClassThatImplementsAndExtends */', + 'expected' => 'testFECNClass', + ], + 'interface extends multiple interfaces (not supported)' => [ + 'identifier' => '/* testInterfaceMultiExtends */', + 'expected' => '\Package\FooInterface', + ], + 'parse error - extends keyword, but no class name' => [ + 'identifier' => '/* testMissingExtendsName */', + 'expected' => false, + ], + 'parse error - live coding - no curly braces' => [ + 'identifier' => '/* testParseError */', + 'expected' => false, + ], + ]; + + }//end dataExtendedClass() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindImplementedInterfaceNamesTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindImplementedInterfaceNamesTest.inc new file mode 100644 index 00000000..3246efa2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindImplementedInterfaceNamesTest.inc @@ -0,0 +1,47 @@ + + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames method. + * + * @covers \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames + */ +final class FindImplementedInterfaceNamesTest extends AbstractMethodUnitTest +{ + + + /** + * Test getting a `false` result when a non-existent token is passed. + * + * @return void + */ + public function testNonExistentToken() + { + $result = self::$phpcsFile->findImplementedInterfaceNames(100000); + $this->assertFalse($result); + + }//end testNonExistentToken() + + + /** + * Test getting a `false` result when a token other than one of the supported tokens is passed. + * + * @return void + */ + public function testNotAClass() + { + $token = $this->getTargetToken('/* testNotAClass */', [T_FUNCTION]); + $result = self::$phpcsFile->findImplementedInterfaceNames($token); + $this->assertFalse($result); + + }//end testNotAClass() + + + /** + * Test retrieving the name(s) of the interfaces being implemented by a class. + * + * @param string $identifier Comment which precedes the test case. + * @param array|false $expected Expected function output. + * + * @dataProvider dataImplementedInterface + * + * @return void + */ + public function testFindImplementedInterfaceNames($identifier, $expected) + { + $OOToken = $this->getTargetToken($identifier, [T_CLASS, T_ANON_CLASS, T_INTERFACE, T_ENUM]); + $result = self::$phpcsFile->findImplementedInterfaceNames($OOToken); + $this->assertSame($expected, $result); + + }//end testFindImplementedInterfaceNames() + + + /** + * Data provider for the FindImplementedInterfaceNames test. + * + * @see testFindImplementedInterfaceNames() + * + * @return array|false>> + */ + public static function dataImplementedInterface() + { + return [ + 'interface declaration, no implements' => [ + 'identifier' => '/* testPlainInterface */', + 'expected' => false, + ], + 'class does not implement' => [ + 'identifier' => '/* testNonImplementedClass */', + 'expected' => false, + ], + 'class implements single interface, unqualified' => [ + 'identifier' => '/* testClassImplementsSingle */', + 'expected' => [ + 'testFIINInterface', + ], + ], + 'class implements multiple interfaces' => [ + 'identifier' => '/* testClassImplementsMultiple */', + 'expected' => [ + 'testFIINInterface', + 'testFIINInterface2', + ], + ], + 'class implements single interface, fully qualified' => [ + 'identifier' => '/* testImplementsFullyQualified */', + 'expected' => [ + '\PHP_CodeSniffer\Tests\Core\File\testFIINInterface', + ], + ], + 'class implements single interface, partially qualified' => [ + 'identifier' => '/* testImplementsPartiallyQualified */', + 'expected' => [ + 'Core\File\RelativeInterface', + ], + ], + 'class extends and implements' => [ + 'identifier' => '/* testClassThatExtendsAndImplements */', + 'expected' => [ + 'InterfaceA', + '\NameSpaced\Cat\InterfaceB', + ], + ], + 'class implements and extends' => [ + 'identifier' => '/* testClassThatImplementsAndExtends */', + 'expected' => [ + '\InterfaceA', + 'InterfaceB', + ], + ], + 'enum does not implement' => [ + 'identifier' => '/* testBackedEnumWithoutImplements */', + 'expected' => false, + ], + 'enum implements single interface, unqualified' => [ + 'identifier' => '/* testEnumImplementsSingle */', + 'expected' => [ + 'Colorful', + ], + ], + 'enum implements multiple interfaces, unqualified + fully qualified' => [ + 'identifier' => '/* testBackedEnumImplementsMulti */', + 'expected' => [ + 'Colorful', + '\Deck', + ], + ], + 'anon class implements single interface, unqualified' => [ + 'identifier' => '/* testAnonClassImplementsSingle */', + 'expected' => [ + 'testFIINInterface', + ], + ], + 'parse error - implements keyword, but no interface name' => [ + 'identifier' => '/* testMissingImplementsName */', + 'expected' => false, + ], + 'parse error - live coding - no curly braces' => [ + 'identifier' => '/* testParseError */', + 'expected' => false, + ], + ]; + + }//end dataImplementedInterface() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.inc new file mode 100644 index 00000000..5b601075 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.inc @@ -0,0 +1,208 @@ + $foo + $bar, 'b' => true]; + +/* testUseGroup */ +use Vendor\Package\{ClassA as A, ClassB, ClassC as C}; + +$a = [ + /* testArrowFunctionArrayValue */ + 'a' => fn() => 1, + 'b' => fn() => 1, +]; + +/* testStaticArrowFunction */ +static fn ($a) => $a; + +/* testArrowFunctionReturnValue */ +fn(): array => [a($a, $b)]; + +/* testArrowFunctionAsArgument */ +$foo = foo( + fn() => bar() +); + +/* testArrowFunctionWithArrayAsArgument */ +$foo = foo( + fn() => [$row[0], $row[3]] +); + +$match = match ($a) { + /* testMatchCase */ + 1 => 'foo', + /* testMatchDefault */ + default => 'bar' +}; + +$match = match ($a) { + /* testMatchMultipleCase */ + 1, 2, => $a * $b, + /* testMatchDefaultComma */ + default, => 'something' +}; + +match ($pressedKey) { + /* testMatchFunctionCall */ + Key::RETURN_ => save($value, $user) +}; + +$result = match (true) { + /* testMatchFunctionCallArm */ + str_contains($text, 'Welcome') || str_contains($text, 'Hello') => 'en', + str_contains($text, 'Bienvenue') || str_contains($text, 'Bonjour') => 'fr', + default => 'pl' +}; + +/* testMatchClosure */ +$result = match ($key) { + 1 => function($a, $b) {}, + 2 => function($b, $c) {}, +}; + +/* testMatchArray */ +$result = match ($key) { + 1 => [1,2,3], + 2 => [1 => one($a, $b), 2 => two($b, $c)], + 3 => [], +}; + +/* testNestedMatch */ +$result = match ($key) { + 1 => match ($key) { + 1 => 'one', + 2 => 'two', + }, + 2 => match ($key) { + 1 => 'two', + 2 => 'one', + }, +}; + +return 0; + +/* testOpenTag */ +?> +

Test

+', foo(), ''; + +/* testOpenTagWithEcho */ +?> +

Test

+', foo(), ''; + +$value = [ + /* testPrecededByArrowFunctionInArray - Expected */ + Url::make('View Song', fn($song) => $song->url()) + /* testPrecededByArrowFunctionInArray */ + ->onlyOnDetail(), + + new Panel('Information', [ + Text::make('Title') + ]), +]; + +switch ($foo) { + /* testCaseStatement */ + case 1: + /* testInsideCaseStatement */ + $var = doSomething(); + /* testInsideCaseBreakStatement */ + break 1; + + case 2: + /* testInsideCaseContinueStatement */ + continue 1; + + case 3: + /* testInsideCaseReturnStatement */ + return false; + + case 4: + /* testInsideCaseExitStatement */ + exit(1); + + case 5: + /* testInsideCaseThrowStatement */ + throw new Exception(); + + case 6: + $var = doSomething(); + /* testInsideCaseGotoStatement */ + goto myLabel; + + /* testDefaultStatement */ + default: + /* testInsideDefaultContinueStatement */ + continue $var; +} + +myLabel: +do_something(); + +match ($var) { + true => + /* test437ClosureDeclaration */ + function ($var) { + /* test437EchoNestedWithinClosureWithinMatch */ + echo $var, 'text', PHP_EOL; + }, + default => false +}; + +match ($var) { + /* test437NestedLongArrayWithinMatch */ + 'a' => array( 1, 2.5, $var), + /* test437NestedFunctionCallWithinMatch */ + 'b' => functionCall( 11, $var, 50.50), + /* test437NestedArrowFunctionWithinMatch */ + 'c' => fn($p1, /* test437FnSecondParamWithinMatch */ $p2) => $p1 + $p2, + default => false +}; + +callMe($paramA, match ($var) { + /* test437NestedLongArrayWithinNestedMatch */ + 'a' => array( 1, 2.5, $var), + /* test437NestedFunctionCallWithinNestedMatch */ + 'b' => functionCall( 11, $var, 50.50), + /* test437NestedArrowFunctionWithinNestedMatch */ + 'c' => fn($p1, /* test437FnSecondParamWithinNestedMatch */ $p2) => $p1 + $p2, + default => false +}); + +match ($var) { + /* test437NestedShortArrayWithinMatch */ + 'a' => [ 1, 2.5, $var], + default => false +}; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.php new file mode 100644 index 00000000..4e0916dd --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.php @@ -0,0 +1,983 @@ + + * @author Juliette Reinders Folmer + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::findStartOfStatement method. + * + * @covers \PHP_CodeSniffer\Files\File::findStartOfStatement + */ +final class FindStartOfStatementTest extends AbstractMethodUnitTest +{ + + + /** + * Test that start of statement is NEVER beyond the "current" token. + * + * @return void + */ + public function testStartIsNeverMoreThanCurrentToken() + { + $tokens = self::$phpcsFile->getTokens(); + $errors = []; + + for ($i = 0; $i < self::$phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + $start = self::$phpcsFile->findStartOfStatement($i); + + // Collect all the errors. + if ($start > $i) { + $errors[] = sprintf( + 'Start of statement for token %1$d (%2$s: %3$s) on line %4$d is %5$d (%6$s), which is more than %1$d', + $i, + $tokens[$i]['type'], + $tokens[$i]['content'], + $tokens[$i]['line'], + $start, + $tokens[$start]['type'] + ); + } + } + + $this->assertSame([], $errors); + + }//end testStartIsNeverMoreThanCurrentToken() + + + /** + * Test a simple assignment. + * + * @return void + */ + public function testSimpleAssignment() + { + $start = $this->getTargetToken('/* testSimpleAssignment */', T_SEMICOLON); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 5), $found); + + }//end testSimpleAssignment() + + + /** + * Test a function call. + * + * @return void + */ + public function testFunctionCall() + { + $start = $this->getTargetToken('/* testFunctionCall */', T_CLOSE_PARENTHESIS); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 6), $found); + + }//end testFunctionCall() + + + /** + * Test a function call. + * + * @return void + */ + public function testFunctionCallArgument() + { + $start = $this->getTargetToken('/* testFunctionCallArgument */', T_VARIABLE, '$b'); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame($start, $found); + + }//end testFunctionCallArgument() + + + /** + * Test a direct call to a control structure. + * + * @return void + */ + public function testControlStructure() + { + $start = $this->getTargetToken('/* testControlStructure */', T_CLOSE_CURLY_BRACKET); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 6), $found); + + }//end testControlStructure() + + + /** + * Test the assignment of a closure. + * + * @return void + */ + public function testClosureAssignment() + { + $start = $this->getTargetToken('/* testClosureAssignment */', T_CLOSE_CURLY_BRACKET); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 11), $found); + + }//end testClosureAssignment() + + + /** + * Test using a heredoc in a function argument. + * + * @return void + */ + public function testHeredocFunctionArg() + { + // Find the start of the function. + $start = $this->getTargetToken('/* testHeredocFunctionArg */', T_SEMICOLON); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 10), $found); + + // Find the start of the heredoc. + $start -= 4; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 4), $found); + + // Find the start of the last arg. + $start += 2; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame($start, $found); + + }//end testHeredocFunctionArg() + + + /** + * Test parts of a switch statement. + * + * @return void + */ + public function testSwitch() + { + // Find the start of the switch. + $start = $this->getTargetToken('/* testSwitch */', T_CLOSE_CURLY_BRACKET); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 47), $found); + + // Find the start of default case. + $start -= 5; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 6), $found); + + // Find the start of the second case. + $start -= 12; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 5), $found); + + // Find the start of the first case. + $start -= 13; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 8), $found); + + // Test inside the first case. + $start--; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 1), $found); + + }//end testSwitch() + + + /** + * Test statements that are array values. + * + * @return void + */ + public function testStatementAsArrayValue() + { + // Test short array syntax. + $start = $this->getTargetToken('/* testStatementAsArrayValue */', T_STRING, 'Datetime'); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 2), $found); + + // Test long array syntax. + $start += 12; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 2), $found); + + // Test same statement outside of array. + $start++; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 9), $found); + + // Test with an array index. + $start += 17; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 5), $found); + + }//end testStatementAsArrayValue() + + + /** + * Test a use group. + * + * @return void + */ + public function testUseGroup() + { + $start = $this->getTargetToken('/* testUseGroup */', T_SEMICOLON); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 23), $found); + + }//end testUseGroup() + + + /** + * Test arrow function as array value. + * + * @return void + */ + public function testArrowFunctionArrayValue() + { + $start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_COMMA); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 7), $found); + + }//end testArrowFunctionArrayValue() + + + /** + * Test static arrow function. + * + * @return void + */ + public function testStaticArrowFunction() + { + $start = $this->getTargetToken('/* testStaticArrowFunction */', T_SEMICOLON); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 11), $found); + + }//end testStaticArrowFunction() + + + /** + * Test arrow function with return value. + * + * @return void + */ + public function testArrowFunctionReturnValue() + { + $start = $this->getTargetToken('/* testArrowFunctionReturnValue */', T_SEMICOLON); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 18), $found); + + }//end testArrowFunctionReturnValue() + + + /** + * Test arrow function used as a function argument. + * + * @return void + */ + public function testArrowFunctionAsArgument() + { + $start = $this->getTargetToken('/* testArrowFunctionAsArgument */', T_FN); + $start += 8; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 8), $found); + + }//end testArrowFunctionAsArgument() + + + /** + * Test arrow function with arrays used as a function argument. + * + * @return void + */ + public function testArrowFunctionWithArrayAsArgument() + { + $start = $this->getTargetToken('/* testArrowFunctionWithArrayAsArgument */', T_FN); + $start += 17; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 17), $found); + + }//end testArrowFunctionWithArrayAsArgument() + + + /** + * Test simple match expression case. + * + * @return void + */ + public function testMatchCase() + { + $start = $this->getTargetToken('/* testMatchCase */', T_COMMA); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 1), $found); + + }//end testMatchCase() + + + /** + * Test simple match expression default case. + * + * @return void + */ + public function testMatchDefault() + { + $start = $this->getTargetToken('/* testMatchDefault */', T_CONSTANT_ENCAPSED_STRING, "'bar'"); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame($start, $found); + + }//end testMatchDefault() + + + /** + * Test multiple comma-separated match expression case values. + * + * @return void + */ + public function testMatchMultipleCase() + { + $start = $this->getTargetToken('/* testMatchMultipleCase */', T_MATCH_ARROW); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 6), $found); + + $start += 6; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 4), $found); + + }//end testMatchMultipleCase() + + + /** + * Test match expression default case with trailing comma. + * + * @return void + */ + public function testMatchDefaultComma() + { + $start = $this->getTargetToken('/* testMatchDefaultComma */', T_MATCH_ARROW); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 3), $found); + + $start += 2; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame($start, $found); + + }//end testMatchDefaultComma() + + + /** + * Test match expression with function call. + * + * @return void + */ + public function testMatchFunctionCall() + { + $start = $this->getTargetToken('/* testMatchFunctionCall */', T_CLOSE_PARENTHESIS); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 6), $found); + + }//end testMatchFunctionCall() + + + /** + * Test match expression with function call in the arm. + * + * @return void + */ + public function testMatchFunctionCallArm() + { + // Check the first case. + $start = $this->getTargetToken('/* testMatchFunctionCallArm */', T_MATCH_ARROW); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 18), $found); + + // Check the second case. + $start += 24; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 18), $found); + + }//end testMatchFunctionCallArm() + + + /** + * Test match expression with closure. + * + * @return void + */ + public function testMatchClosure() + { + $start = $this->getTargetToken('/* testMatchClosure */', T_LNUMBER); + $start += 14; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 10), $found); + + $start += 17; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 10), $found); + + }//end testMatchClosure() + + + /** + * Test match expression with array declaration. + * + * @return void + */ + public function testMatchArray() + { + // Start of first case statement. + $start = $this->getTargetToken('/* testMatchArray */', T_LNUMBER); + $found = self::$phpcsFile->findStartOfStatement($start); + $this->assertSame($start, $found); + + // Comma after first statement. + $start += 11; + $found = self::$phpcsFile->findStartOfStatement($start); + $this->assertSame(($start - 7), $found); + + // Start of second case statement. + $start += 3; + $found = self::$phpcsFile->findStartOfStatement($start); + $this->assertSame($start, $found); + + // Comma after first statement. + $start += 30; + $found = self::$phpcsFile->findStartOfStatement($start); + $this->assertSame(($start - 26), $found); + + }//end testMatchArray() + + + /** + * Test nested match expressions. + * + * @return void + */ + public function testNestedMatch() + { + $start = $this->getTargetToken('/* testNestedMatch */', T_LNUMBER); + $start += 30; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 26), $found); + + $start -= 4; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 1), $found); + + $start -= 3; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 2), $found); + + }//end testNestedMatch() + + + /** + * Test PHP open tag. + * + * @return void + */ + public function testOpenTag() + { + $start = $this->getTargetToken('/* testOpenTag */', T_OPEN_TAG); + $start += 2; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 1), $found); + + }//end testOpenTag() + + + /** + * Test PHP short open echo tag. + * + * @return void + */ + public function testOpenTagWithEcho() + { + $start = $this->getTargetToken('/* testOpenTagWithEcho */', T_OPEN_TAG_WITH_ECHO); + $start += 3; + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame(($start - 1), $found); + + }//end testOpenTagWithEcho() + + + /** + * Test object call on result of static function call with arrow function as parameter and wrapped within an array. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2849 + * @link https://github.com/squizlabs/PHP_CodeSniffer/commit/fbf67efc3fc0c2a355f5585d49f4f6fe160ff2f9 + * + * @return void + */ + public function testObjectCallPrecededByArrowFunctionAsFunctionCallParameterInArray() + { + $expected = $this->getTargetToken('/* testPrecededByArrowFunctionInArray - Expected */', T_STRING, 'Url'); + + $start = $this->getTargetToken('/* testPrecededByArrowFunctionInArray */', T_STRING, 'onlyOnDetail'); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame($expected, $found); + + }//end testObjectCallPrecededByArrowFunctionAsFunctionCallParameterInArray() + + + /** + * Test finding the start of a statement inside a switch control structure case/default statement. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targets The token to search for after the test marker. + * @param string|int $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/squizlabs/php_codesniffer/issues/3192 + * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/3186/commits/18a0e54735bb9b3850fec266e5f4c50dacf618ea + * + * @dataProvider dataFindStartInsideSwitchCaseDefaultStatements + * + * @return void + */ + public function testFindStartInsideSwitchCaseDefaultStatements($testMarker, $targets, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $targets); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideSwitchCaseDefaultStatements() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideSwitchCaseDefaultStatements() + { + return [ + 'Case keyword should be start of case statement - case itself' => [ + 'testMarker' => '/* testCaseStatement */', + 'targets' => T_CASE, + 'expectedTarget' => T_CASE, + ], + 'Case keyword should be start of case statement - number (what\'s being compared)' => [ + 'testMarker' => '/* testCaseStatement */', + 'targets' => T_LNUMBER, + 'expectedTarget' => T_CASE, + ], + 'Variable should be start of arbitrary assignment statement - variable itself' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Variable should be start of arbitrary assignment statement - equal sign' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => T_EQUAL, + 'expectedTarget' => T_VARIABLE, + ], + 'Variable should be start of arbitrary assignment statement - function call' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => T_STRING, + 'expectedTarget' => T_VARIABLE, + ], + 'Break should be start for contents of the break statement - contents' => [ + 'testMarker' => '/* testInsideCaseBreakStatement */', + 'targets' => T_LNUMBER, + 'expectedTarget' => T_BREAK, + ], + 'Continue should be start for contents of the continue statement - contents' => [ + 'testMarker' => '/* testInsideCaseContinueStatement */', + 'targets' => T_LNUMBER, + 'expectedTarget' => T_CONTINUE, + ], + 'Return should be start for contents of the return statement - contents' => [ + 'testMarker' => '/* testInsideCaseReturnStatement */', + 'targets' => T_FALSE, + 'expectedTarget' => T_RETURN, + ], + 'Exit should be start for contents of the exit statement - close parenthesis' => [ + // Note: not sure if this is actually correct - should this be the open parenthesis ? + 'testMarker' => '/* testInsideCaseExitStatement */', + 'targets' => T_CLOSE_PARENTHESIS, + 'expectedTarget' => T_EXIT, + ], + 'Throw should be start for contents of the throw statement - new keyword' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => T_NEW, + 'expectedTarget' => T_THROW, + ], + 'Throw should be start for contents of the throw statement - exception name' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => T_STRING, + 'expectedTarget' => T_THROW, + ], + 'Throw should be start for contents of the throw statement - close parenthesis' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => T_CLOSE_PARENTHESIS, + 'expectedTarget' => T_THROW, + ], + 'Goto should be start for contents of the goto statement - goto label' => [ + 'testMarker' => '/* testInsideCaseGotoStatement */', + 'targets' => T_STRING, + 'expectedTarget' => T_GOTO, + ], + 'Goto should be start for contents of the goto statement - semicolon' => [ + 'testMarker' => '/* testInsideCaseGotoStatement */', + 'targets' => T_SEMICOLON, + 'expectedTarget' => T_GOTO, + ], + 'Default keyword should be start of default statement - default itself' => [ + 'testMarker' => '/* testDefaultStatement */', + 'targets' => T_DEFAULT, + 'expectedTarget' => T_DEFAULT, + ], + 'Return should be start for contents of the return statement (inside default) - variable' => [ + 'testMarker' => '/* testInsideDefaultContinueStatement */', + 'targets' => T_VARIABLE, + 'expectedTarget' => T_CONTINUE, + ], + ]; + + }//end dataFindStartInsideSwitchCaseDefaultStatements() + + + /** + * Test finding the start of a statement inside a closed scope nested within a match expressions. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideClosedScopeNestedWithinMatch + * + * @return void + */ + public function testFindStartInsideClosedScopeNestedWithinMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideClosedScopeNestedWithinMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideClosedScopeNestedWithinMatch() + { + return [ + // These were already working correctly. + 'Closure function keyword should be start of closure - closure keyword' => [ + 'testMarker' => '/* test437ClosureDeclaration */', + 'target' => T_CLOSURE, + 'expectedTarget' => T_CLOSURE, + ], + 'Open curly is a statement/expression opener - open curly' => [ + 'testMarker' => '/* test437ClosureDeclaration */', + 'target' => T_OPEN_CURLY_BRACKET, + 'expectedTarget' => T_OPEN_CURLY_BRACKET, + ], + + 'Echo should be start for expression - echo keyword' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_ECHO, + 'expectedTarget' => T_ECHO, + ], + 'Echo should be start for expression - variable' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_ECHO, + ], + 'Echo should be start for expression - comma' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_COMMA, + 'expectedTarget' => T_ECHO, + ], + + // These were not working correctly and would previously return the close curly of the match expression. + 'First token after comma in echo expression should be start for expression - text string' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_CONSTANT_ENCAPSED_STRING, + 'expectedTarget' => T_CONSTANT_ENCAPSED_STRING, + ], + 'First token after comma in echo expression - PHP_EOL constant' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_STRING, + 'expectedTarget' => T_STRING, + ], + 'First token after comma in echo expression - semicolon' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_SEMICOLON, + 'expectedTarget' => T_STRING, + ], + ]; + + }//end dataFindStartInsideClosedScopeNestedWithinMatch() + + + /** + * Test finding the start of a statement for a token within a set of parentheses within a match expressions. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideParenthesesNestedWithinMatch + * + * @return void + */ + public function testFindStartInsideParenthesesNestedWithinMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideParenthesesNestedWithinMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideParenthesesNestedWithinMatch() + { + return [ + 'Array item itself should be start for first array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Array item itself should be start for second array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + 'Array item itself should be start for third array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + + 'Parameter itself should be start for first param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Parameter itself should be start for second param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for third param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + + 'Parameter itself should be start for first param declared in arrow function' => [ + 'testMarker' => '/* test437NestedArrowFunctionWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for second param declared in arrow function' => [ + 'testMarker' => '/* test437FnSecondParamWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + ]; + + }//end dataFindStartInsideParenthesesNestedWithinMatch() + + + /** + * Test finding the start of a statement for a token within a set of parentheses within a match expressions, + * which itself is nested within parentheses. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideParenthesesNestedWithinNestedMatch + * + * @return void + */ + public function testFindStartInsideParenthesesNestedWithinNestedMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideParenthesesNestedWithinNestedMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideParenthesesNestedWithinNestedMatch() + { + return [ + 'Array item itself should be start for first array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Array item itself should be start for second array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + 'Array item itself should be start for third array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + + 'Parameter itself should be start for first param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Parameter itself should be start for second param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for third param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + + 'Parameter itself should be start for first param declared in arrow function' => [ + 'testMarker' => '/* test437NestedArrowFunctionWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for second param declared in arrow function' => [ + 'testMarker' => '/* test437FnSecondParamWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + ]; + + }//end dataFindStartInsideParenthesesNestedWithinNestedMatch() + + + /** + * Test finding the start of a statement for a token within a short array within a match expressions. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideShortArrayNestedWithinMatch + * + * @return void + */ + public function testFindStartInsideShortArrayNestedWithinMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideShortArrayNestedWithinMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideShortArrayNestedWithinMatch() + { + return [ + 'Array item itself should be start for first array item' => [ + 'testMarker' => '/* test437NestedShortArrayWithinMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Array item itself should be start for second array item' => [ + 'testMarker' => '/* test437NestedShortArrayWithinMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + 'Array item itself should be start for third array item' => [ + 'testMarker' => '/* test437NestedShortArrayWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + ]; + + }//end dataFindStartInsideShortArrayNestedWithinMatch() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetClassPropertiesTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetClassPropertiesTest.inc new file mode 100644 index 00000000..2490a096 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetClassPropertiesTest.inc @@ -0,0 +1,58 @@ + + * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getClassProperties method. + * + * @covers \PHP_CodeSniffer\Files\File::getClassProperties + */ +final class GetClassPropertiesTest extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an expected exception when a non class token is passed. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $tokenType The type of token to look for after the marker. + * + * @dataProvider dataNotAClassException + * + * @return void + */ + public function testNotAClassException($testMarker, $tokenType) + { + $this->expectRunTimeException('$stackPtr must be of type T_CLASS'); + + $target = $this->getTargetToken($testMarker, $tokenType); + self::$phpcsFile->getClassProperties($target); + + }//end testNotAClassException() + + + /** + * Data provider. + * + * @see testNotAClassException() For the array format. + * + * @return array> + */ + public static function dataNotAClassException() + { + return [ + 'interface' => [ + 'testMarker' => '/* testNotAClass */', + 'tokenType' => T_INTERFACE, + ], + 'anon-class' => [ + 'testMarker' => '/* testAnonClass */', + 'tokenType' => T_ANON_CLASS, + ], + 'enum' => [ + 'testMarker' => '/* testEnum */', + 'tokenType' => T_ENUM, + ], + ]; + + }//end dataNotAClassException() + + + /** + * Test retrieving the properties for a class declaration. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected Expected function output. + * + * @dataProvider dataGetClassProperties + * + * @return void + */ + public function testGetClassProperties($testMarker, $expected) + { + $class = $this->getTargetToken($testMarker, T_CLASS); + $result = self::$phpcsFile->getClassProperties($class); + $this->assertSame($expected, $result); + + }//end testGetClassProperties() + + + /** + * Data provider. + * + * @see testGetClassProperties() For the array format. + * + * @return array>> + */ + public static function dataGetClassProperties() + { + return [ + 'no-properties' => [ + 'testMarker' => '/* testClassWithoutProperties */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'abstract' => [ + 'testMarker' => '/* testAbstractClass */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'final' => [ + 'testMarker' => '/* testFinalClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => false, + ], + ], + 'readonly' => [ + 'testMarker' => '/* testReadonlyClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'final-readonly' => [ + 'testMarker' => '/* testFinalReadonlyClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => true, + ], + ], + 'readonly-final' => [ + 'testMarker' => '/* testReadonlyFinalClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => true, + ], + ], + 'abstract-readonly' => [ + 'testMarker' => '/* testAbstractReadonlyClass */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'readonly-abstract' => [ + 'testMarker' => '/* testReadonlyAbstractClass */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'comments-and-new-lines' => [ + 'testMarker' => '/* testWithCommentsAndNewLines */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'no-properties-with-docblock' => [ + 'testMarker' => '/* testWithDocblockWithoutProperties */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'abstract-final-parse-error' => [ + 'testMarker' => '/* testParseErrorAbstractFinal */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => true, + 'is_readonly' => false, + ], + ], + ]; + + }//end dataGetClassProperties() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.inc new file mode 100644 index 00000000..e7684daa --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.inc @@ -0,0 +1,91 @@ + $v) { + + /* condition 11-2: try */ + try { + --$k; + + /* condition 11-3: catch */ + } catch (Exception $e) { + /* testInException */ + echo 'oh darn'; + /* condition 11-4: finally */ + } finally { + return true; + } + } + + $a++; + } + break; + + /* condition 8b: default */ + default: + /* testInDefault */ + $return = 'nada'; + return $return; + } + } + } + } + } + } + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.php new file mode 100644 index 00000000..9d6eecc6 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.php @@ -0,0 +1,494 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getCondition and \PHP_CodeSniffer\Files\File:hasCondition methods. + * + * @covers \PHP_CodeSniffer\Files\File::getCondition + * @covers \PHP_CodeSniffer\Files\File::hasCondition + */ +final class GetConditionTest extends AbstractMethodUnitTest +{ + + /** + * List of all the test markers with their target token in the test case file. + * + * - The startPoint token is left out as it is tested separately. + * - The key is the type of token to look for after the test marker. + * + * @var array + */ + protected static $testTargets = [ + T_VARIABLE => '/* testSeriouslyNestedMethod */', + T_RETURN => '/* testDeepestNested */', + T_ECHO => '/* testInException */', + T_CONSTANT_ENCAPSED_STRING => '/* testInDefault */', + ]; + + /** + * List of all the condition markers in the test case file. + * + * @var array + */ + protected $conditionMarkers = [ + '/* condition 0: namespace */', + '/* condition 1: if */', + '/* condition 2: function */', + '/* condition 3-1: if */', + '/* condition 3-2: else */', + '/* condition 4: if */', + '/* condition 5: nested class */', + '/* condition 6: class method */', + '/* condition 7: switch */', + '/* condition 8a: case */', + '/* condition 9: while */', + '/* condition 10-1: if */', + '/* condition 11-1: nested anonymous class */', + '/* condition 12: nested anonymous class method */', + '/* condition 13: closure */', + '/* condition 10-2: elseif */', + '/* condition 10-3: foreach */', + '/* condition 11-2: try */', + '/* condition 11-3: catch */', + '/* condition 11-4: finally */', + '/* condition 8b: default */', + ]; + + /** + * Base array with all the scope opening tokens. + * + * This array is merged with expected result arrays for various unit tests + * to make sure all possible conditions are tested. + * + * This array should be kept in sync with the Tokens::$scopeOpeners array. + * This array isn't auto-generated based on the array in Tokens as for these + * tests we want to have access to the token constant names, not just their values. + * + * @var array + */ + protected $conditionDefaults = [ + 'T_CLASS' => false, + 'T_ANON_CLASS' => false, + 'T_INTERFACE' => false, + 'T_TRAIT' => false, + 'T_NAMESPACE' => false, + 'T_FUNCTION' => false, + 'T_CLOSURE' => false, + 'T_IF' => false, + 'T_SWITCH' => false, + 'T_CASE' => false, + 'T_DECLARE' => false, + 'T_DEFAULT' => false, + 'T_WHILE' => false, + 'T_ELSE' => false, + 'T_ELSEIF' => false, + 'T_FOR' => false, + 'T_FOREACH' => false, + 'T_DO' => false, + 'T_TRY' => false, + 'T_CATCH' => false, + 'T_FINALLY' => false, + 'T_PROPERTY' => false, + 'T_OBJECT' => false, + 'T_USE' => false, + ]; + + /** + * Cache for the test token stack pointers. + * + * @var array + */ + protected static $testTokens = []; + + /** + * Cache for the marker token stack pointers. + * + * @var array + */ + protected static $markerTokens = []; + + + /** + * Set up the token position caches for the tests. + * + * Retrieves the test tokens and marker token stack pointer positions + * only once and caches them as they won't change between the tests anyway. + * + * @before + * + * @return void + */ + protected function setUpCaches() + { + if (empty(self::$testTokens) === true) { + foreach (self::$testTargets as $targetToken => $marker) { + self::$testTokens[$marker] = $this->getTargetToken($marker, $targetToken); + } + } + + if (empty(self::$markerTokens) === true) { + foreach ($this->conditionMarkers as $marker) { + self::$markerTokens[$marker] = $this->getTargetToken($marker, Tokens::$scopeOpeners); + } + } + + }//end setUpCaches() + + + /** + * Test passing a non-existent token pointer. + * + * @return void + */ + public function testNonExistentToken() + { + $result = self::$phpcsFile->getCondition(100000, T_CLASS); + $this->assertFalse($result); + + $result = self::$phpcsFile->hasCondition(100000, T_IF); + $this->assertFalse($result); + + }//end testNonExistentToken() + + + /** + * Test passing a non conditional token. + * + * @return void + */ + public function testNonConditionalToken() + { + $targetType = T_STRING; + $stackPtr = $this->getTargetToken('/* testStartPoint */', $targetType); + + $result = self::$phpcsFile->getCondition($stackPtr, T_IF); + $this->assertFalse($result); + + $result = self::$phpcsFile->hasCondition($stackPtr, Tokens::$ooScopeTokens); + $this->assertFalse($result); + + }//end testNonConditionalToken() + + + /** + * Test retrieving a specific condition from a tokens "conditions" array. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the marker for the expected stack pointer result as a value. + * + * @dataProvider dataGetCondition + * + * @return void + */ + public function testGetCondition($testMarker, $expectedResults) + { + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + if (is_string($expected) === true) { + $expected = self::$markerTokens[$expected]; + } + + $result = self::$phpcsFile->getCondition($stackPtr, constant($conditionType)); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType}" + ); + } + + }//end testGetCondition() + + + /** + * Data provider. + * + * Only the conditions which are expected to be *found* need to be listed here. + * All other potential conditions will automatically also be tested and will expect + * `false` as a result. + * + * @see testGetCondition() For the array format. + * + * @return array>> + */ + public static function dataGetCondition() + { + return [ + 'testSeriouslyNestedMethod' => [ + 'testMarker' => '/* testSeriouslyNestedMethod */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_IF' => '/* condition 1: if */', + 'T_ELSE' => '/* condition 3-2: else */', + ], + ], + 'testDeepestNested' => [ + 'testMarker' => '/* testDeepestNested */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_ANON_CLASS' => '/* condition 11-1: nested anonymous class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_CLOSURE' => '/* condition 13: closure */', + 'T_IF' => '/* condition 1: if */', + 'T_SWITCH' => '/* condition 7: switch */', + 'T_CASE' => '/* condition 8a: case */', + 'T_WHILE' => '/* condition 9: while */', + 'T_ELSE' => '/* condition 3-2: else */', + ], + ], + 'testInException' => [ + 'testMarker' => '/* testInException */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_IF' => '/* condition 1: if */', + 'T_SWITCH' => '/* condition 7: switch */', + 'T_CASE' => '/* condition 8a: case */', + 'T_WHILE' => '/* condition 9: while */', + 'T_ELSE' => '/* condition 3-2: else */', + 'T_FOREACH' => '/* condition 10-3: foreach */', + 'T_CATCH' => '/* condition 11-3: catch */', + ], + ], + 'testInDefault' => [ + 'testMarker' => '/* testInDefault */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_IF' => '/* condition 1: if */', + 'T_SWITCH' => '/* condition 7: switch */', + 'T_DEFAULT' => '/* condition 8b: default */', + 'T_ELSE' => '/* condition 3-2: else */', + ], + ], + ]; + + }//end dataGetCondition() + + + /** + * Test retrieving a specific condition from a tokens "conditions" array. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the marker for the expected stack pointer result as a value. + * + * @dataProvider dataGetConditionReversed + * + * @return void + */ + public function testGetConditionReversed($testMarker, $expectedResults) + { + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + if (is_string($expected) === true) { + $expected = self::$markerTokens[$expected]; + } + + $result = self::$phpcsFile->getCondition($stackPtr, constant($conditionType), false); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType} (reversed)" + ); + } + + }//end testGetConditionReversed() + + + /** + * Data provider. + * + * Only the conditions which are expected to be *found* need to be listed here. + * All other potential conditions will automatically also be tested and will expect + * `false` as a result. + * + * @see testGetConditionReversed() For the array format. + * + * @return array>> + */ + public static function dataGetConditionReversed() + { + $data = self::dataGetCondition(); + + // Set up the data for the reversed results. + $data['testSeriouslyNestedMethod']['expectedResults']['T_IF'] = '/* condition 4: if */'; + + $data['testDeepestNested']['expectedResults']['T_FUNCTION'] = '/* condition 12: nested anonymous class method */'; + $data['testDeepestNested']['expectedResults']['T_IF'] = '/* condition 10-1: if */'; + + $data['testInException']['expectedResults']['T_FUNCTION'] = '/* condition 6: class method */'; + $data['testInException']['expectedResults']['T_IF'] = '/* condition 4: if */'; + + $data['testInDefault']['expectedResults']['T_FUNCTION'] = '/* condition 6: class method */'; + $data['testInDefault']['expectedResults']['T_IF'] = '/* condition 4: if */'; + + return $data; + + }//end dataGetConditionReversed() + + + /** + * Test whether a token has a condition of a certain type. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the expected result as a value. + * + * @dataProvider dataHasCondition + * + * @return void + */ + public function testHasCondition($testMarker, $expectedResults) + { + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + $result = self::$phpcsFile->hasCondition($stackPtr, constant($conditionType)); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType}" + ); + } + + }//end testHasCondition() + + + /** + * Data Provider. + * + * Only list the "true" conditions in the $results array. + * All other potential conditions will automatically also be tested + * and will expect "false" as a result. + * + * @see testHasCondition() For the array format. + * + * @return array>> + */ + public static function dataHasCondition() + { + return [ + 'testSeriouslyNestedMethod' => [ + 'testMarker' => '/* testSeriouslyNestedMethod */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_IF' => true, + 'T_ELSE' => true, + ], + ], + 'testDeepestNested' => [ + 'testMarker' => '/* testDeepestNested */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_ANON_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_CLOSURE' => true, + 'T_IF' => true, + 'T_SWITCH' => true, + 'T_CASE' => true, + 'T_WHILE' => true, + 'T_ELSE' => true, + ], + ], + 'testInException' => [ + 'testMarker' => '/* testInException */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_IF' => true, + 'T_SWITCH' => true, + 'T_CASE' => true, + 'T_WHILE' => true, + 'T_ELSE' => true, + 'T_FOREACH' => true, + 'T_CATCH' => true, + ], + ], + 'testInDefault' => [ + 'testMarker' => '/* testInDefault */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_IF' => true, + 'T_SWITCH' => true, + 'T_DEFAULT' => true, + 'T_ELSE' => true, + ], + ], + ]; + + }//end dataHasCondition() + + + /** + * Test whether a token has a condition of a certain type, with multiple allowed possibilities. + * + * @return void + */ + public function testHasConditionMultipleTypes() + { + $stackPtr = self::$testTokens['/* testInException */']; + + $result = self::$phpcsFile->hasCondition($stackPtr, [T_TRY, T_FINALLY]); + $this->assertFalse( + $result, + 'Failed asserting that "testInException" does not have a "try" nor a "finally" condition' + ); + + $result = self::$phpcsFile->hasCondition($stackPtr, [T_TRY, T_CATCH, T_FINALLY]); + $this->assertTrue( + $result, + 'Failed asserting that "testInException" has a "try", "catch" or "finally" condition' + ); + + $stackPtr = self::$testTokens['/* testSeriouslyNestedMethod */']; + + $result = self::$phpcsFile->hasCondition($stackPtr, [T_ANON_CLASS, T_CLOSURE]); + $this->assertFalse( + $result, + 'Failed asserting that "testSeriouslyNestedMethod" does not have an anonymous class nor a closure condition' + ); + + $result = self::$phpcsFile->hasCondition($stackPtr, Tokens::$ooScopeTokens); + $this->assertTrue( + $result, + 'Failed asserting that "testSeriouslyNestedMethod" has an OO Scope token condition' + ); + + }//end testHasConditionMultipleTypes() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.js b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.js new file mode 100644 index 00000000..ee0a76a4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.js @@ -0,0 +1,23 @@ +/* testInvalidTokenPassed */ +print something; + +var object = +{ + /* testClosure */ + propertyName: function () {} +} + +/* testFunction */ +function functionName() {} + +/* testClass */ +class ClassName +{ + /* testMethod */ + methodName() { + return false; + } +} + +/* testFunctionUnicode */ +function π() {} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.php new file mode 100644 index 00000000..5bdb56e2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.php @@ -0,0 +1,158 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameJSTest extends AbstractMethodUnitTest +{ + + /** + * The file extension of the test case file (without leading dot). + * + * @var string + */ + protected static $fileExtension = 'js'; + + + /** + * Test receiving an expected exception when a non-supported token is passed. + * + * @return void + */ + public function testInvalidTokenPassed() + { + $this->expectRunTimeException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); + + $target = $this->getTargetToken('/* testInvalidTokenPassed */', T_STRING); + self::$phpcsFile->getDeclarationName($target); + + }//end testInvalidTokenPassed() + + + /** + * Test receiving "null" when passed an anonymous construct or in case of a parse error. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationNameNull + * + * @return void + */ + public function testGetDeclarationNameNull($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + + /** + * Data provider. + * + * @see GetDeclarationNameTest::testGetDeclarationNameNull() + * + * @return array> + */ + public static function dataGetDeclarationNameNull() + { + return [ + 'closure' => [ + 'testMarker' => '/* testClosure */', + 'targetType' => T_CLOSURE, + ], + ]; + + }//end dataGetDeclarationNameNull() + + + /** + * Test retrieving the name of a function or OO structure. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected Expected function output. + * @param array|null $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationName + * + * @return void + */ + public function testGetDeclarationName($testMarker, $expected, $targetType=null) + { + if (isset($targetType) === false) { + $targetType = [ + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_ENUM, + T_FUNCTION, + ]; + } + + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertSame($expected, $result); + + }//end testGetDeclarationName() + + + /** + * Data provider. + * + * @see GetDeclarationNameTest::testGetDeclarationName() + * + * @return array>> + */ + public static function dataGetDeclarationName() + { + return [ + 'function' => [ + 'testMarker' => '/* testFunction */', + 'expected' => 'functionName', + ], + 'class' => [ + 'testMarker' => '/* testClass */', + 'expected' => 'ClassName', + 'targetType' => [ + T_CLASS, + T_STRING, + ], + ], + 'function-unicode-name' => [ + 'testMarker' => '/* testFunctionUnicode */', + 'expected' => 'π', + ], + ]; + + }//end dataGetDeclarationName() + + + /** + * Test retrieving the name of JS ES6 class method. + * + * @return void + */ + public function testGetDeclarationNameES6Method() + { + $target = $this->getTargetToken('/* testMethod */', [T_CLASS, T_INTERFACE, T_TRAIT, T_FUNCTION]); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertSame('methodName', $result); + + }//end testGetDeclarationNameES6Method() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError1Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError1Test.inc new file mode 100644 index 00000000..451d4dfb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError1Test.inc @@ -0,0 +1,5 @@ + + * @copyright 2025 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameParseError1Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving "null" in case of a parse error. + * + * @return void + */ + public function testGetDeclarationNameNull() + { + $target = $this->getTargetToken('/* testLiveCoding */', T_FUNCTION); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError2Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError2Test.inc new file mode 100644 index 00000000..e9a61cf4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError2Test.inc @@ -0,0 +1,6 @@ + + * @copyright 2025 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameParseError2Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving "null" in case of a parse error. + * + * @return void + */ + public function testGetDeclarationNameNull() + { + $target = $this->getTargetToken('/* testLiveCoding */', T_FUNCTION); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameTest.inc new file mode 100644 index 00000000..a7a53c9a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameTest.inc @@ -0,0 +1,98 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameTest extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an expected exception when a non-supported token is passed. + * + * @return void + */ + public function testInvalidTokenPassed() + { + $this->expectRunTimeException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); + + $target = $this->getTargetToken('/* testInvalidTokenPassed */', T_STRING); + self::$phpcsFile->getDeclarationName($target); + + }//end testInvalidTokenPassed() + + + /** + * Test receiving "null" when passed an anonymous construct or in case of a parse error. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationNameNull + * + * @return void + */ + public function testGetDeclarationNameNull($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + + /** + * Data provider. + * + * @see testGetDeclarationNameNull() For the array format. + * + * @return array> + */ + public static function dataGetDeclarationNameNull() + { + return [ + 'closure' => [ + 'testMarker' => '/* testClosure */', + 'targetType' => T_CLOSURE, + ], + 'anon-class-with-parentheses' => [ + 'testMarker' => '/* testAnonClassWithParens */', + 'targetType' => T_ANON_CLASS, + ], + 'anon-class-with-parentheses-2' => [ + 'testMarker' => '/* testAnonClassWithParens2 */', + 'targetType' => T_ANON_CLASS, + ], + 'anon-class-without-parentheses' => [ + 'testMarker' => '/* testAnonClassWithoutParens */', + 'targetType' => T_ANON_CLASS, + ], + 'anon-class-extends-without-parentheses' => [ + 'testMarker' => '/* testAnonClassExtendsWithoutParens */', + 'targetType' => T_ANON_CLASS, + ], + ]; + + }//end dataGetDeclarationNameNull() + + + /** + * Test retrieving the name of a function or OO structure. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected Expected function output. + * @param int|string|null $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationName + * + * @return void + */ + public function testGetDeclarationName($testMarker, $expected, $targetType=null) + { + if (isset($targetType) === false) { + $targetType = [ + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_ENUM, + T_FUNCTION, + ]; + } + + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertSame($expected, $result); + + }//end testGetDeclarationName() + + + /** + * Data provider. + * + * @see testGetDeclarationName() For the array format. + * + * @return array> + */ + public static function dataGetDeclarationName() + { + return [ + 'function' => [ + 'testMarker' => '/* testFunction */', + 'expected' => 'functionName', + ], + 'function-return-by-reference' => [ + 'testMarker' => '/* testFunctionReturnByRef */', + 'expected' => 'functionNameByRef', + ], + 'class' => [ + 'testMarker' => '/* testClass */', + 'expected' => 'ClassName', + ], + 'method' => [ + 'testMarker' => '/* testMethod */', + 'expected' => 'methodName', + ], + 'abstract-method' => [ + 'testMarker' => '/* testAbstractMethod */', + 'expected' => 'abstractMethodName', + ], + 'method-return-by-reference' => [ + 'testMarker' => '/* testMethodReturnByRef */', + 'expected' => 'MethodNameByRef', + ], + 'extended-class' => [ + 'testMarker' => '/* testExtendedClass */', + 'expected' => 'ExtendedClass', + ], + 'interface' => [ + 'testMarker' => '/* testInterface */', + 'expected' => 'InterfaceName', + ], + 'trait' => [ + 'testMarker' => '/* testTrait */', + 'expected' => 'TraitName', + ], + 'function-name-ends-with-number' => [ + 'testMarker' => '/* testFunctionEndingWithNumber */', + 'expected' => 'ValidNameEndingWithNumber5', + ], + 'class-with-numbers-in-name' => [ + 'testMarker' => '/* testClassWithNumber */', + 'expected' => 'ClassWith1Number', + ], + 'interface-with-numbers-in-name' => [ + 'testMarker' => '/* testInterfaceWithNumbers */', + 'expected' => 'InterfaceWith12345Numbers', + ], + 'class-with-comments-and-new-lines' => [ + 'testMarker' => '/* testClassWithCommentsAndNewLines */', + 'expected' => 'ClassWithCommentsAndNewLines', + ], + 'function-named-fn' => [ + 'testMarker' => '/* testFunctionFn */', + 'expected' => 'fn', + ], + 'enum-pure' => [ + 'testMarker' => '/* testPureEnum */', + 'expected' => 'Foo', + ], + 'enum-backed-space-between-name-and-colon' => [ + 'testMarker' => '/* testBackedEnumSpaceBetweenNameAndColon */', + 'expected' => 'Hoo', + ], + 'enum-backed-no-space-between-name-and-colon' => [ + 'testMarker' => '/* testBackedEnumNoSpaceBetweenNameAndColon */', + 'expected' => 'Suit', + ], + 'function-return-by-reference-with-reserved-keyword-each' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordEach */', + 'expected' => 'each', + ], + 'function-return-by-reference-with-reserved-keyword-parent' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordParent */', + 'expected' => 'parent', + ], + 'function-return-by-reference-with-reserved-keyword-self' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordSelf */', + 'expected' => 'self', + ], + 'function-return-by-reference-with-reserved-keyword-static' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordStatic */', + 'expected' => 'static', + ], + ]; + + }//end dataGetDeclarationName() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.inc new file mode 100644 index 00000000..b5fcea94 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.inc @@ -0,0 +1,403 @@ + 'a', 'b' => 'b' ), + /* testGroupPrivate 3 */ + $varQ = 'string', + /* testGroupPrivate 4 */ + $varR = 123, + /* testGroupPrivate 5 */ + $varS = ONE / self::THREE, + /* testGroupPrivate 6 */ + $varT = [ + 'a' => 'a', + 'b' => 'b' + ], + /* testGroupPrivate 7 */ + $varU = __DIR__ . "/base"; + + + /* testMethodParam */ + public function methodName($param) { + /* testImportedGlobal */ + global $importedGlobal = true; + + /* testLocalVariable */ + $localVariable = true; + } + + /* testPropertyAfterMethod */ + private static $varV = true; + + /* testMessyNullableType */ + public /* comment + */ ? //comment + array $foo = []; + + /* testNamespaceType */ + public \MyNamespace\MyClass $foo; + + /* testNullableNamespaceType 1 */ + private ?ClassName $nullableClassType; + + /* testNullableNamespaceType 2 */ + protected ?Folder\ClassName $nullableClassType2; + + /* testMultilineNamespaceType */ + public \MyNamespace /** comment *\/ comment */ + \MyClass /* comment */ + \Foo $foo; + +} + +interface Base +{ + /* testInterfaceProperty */ + protected $anonymous; +} + +/* testGlobalVariable */ +$globalVariable = true; + +/* testNotAVariable */ +return; + +$a = ( $foo == $bar ? new stdClass() : + new class() { + /* testNestedProperty 1 */ + public $var = true; + + /* testNestedMethodParam 1 */ + public function something($var = false) {} + } +); + +function_call( 'param', new class { + /* testNestedProperty 2 */ + public $year = 2017; + + /* testNestedMethodParam 2 */ + public function __construct( $open, $post_id ) {} +}, 10, 2 ); + +class PHP8Mixed { + /* testPHP8MixedTypeHint */ + public static miXed $mixed; + + /* testPHP8MixedTypeHintNullable */ + // Intentional fatal error - nullability is not allowed with mixed, but that's not the concern of the method. + private ?mixed $nullableMixed; +} + +class NSOperatorInType { + /* testNamespaceOperatorTypeHint */ + public ?namespace\Name $prop; +} + +$anon = class() { + /* testPHP8UnionTypesSimple */ + public int|float $unionTypeSimple; + + /* testPHP8UnionTypesTwoClasses */ + private MyClassA|\Package\MyClassB $unionTypesTwoClasses; + + /* testPHP8UnionTypesAllBaseTypes */ + protected array|bool|int|float|NULL|object|string $unionTypesAllBaseTypes; + + /* testPHP8UnionTypesAllPseudoTypes */ + // Intentional fatal error - mixing types which cannot be combined, but that's not the concern of the method. + var false|mixed|self|parent|iterable|Resource $unionTypesAllPseudoTypes; + + /* testPHP8UnionTypesIllegalTypes */ + // Intentional fatal error - types which are not allowed for properties, but that's not the concern of the method. + // Note: static is also not allowed as a type, but using static for a property type is not supported by the tokenizer. + public callable|void $unionTypesIllegalTypes; + + /* testPHP8UnionTypesNullable */ + // Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. + public ?int|float $unionTypesNullable; + + /* testPHP8PseudoTypeNull */ + // PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. + public null $pseudoTypeNull; + + /* testPHP8PseudoTypeFalse */ + // PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. + public false $pseudoTypeFalse; + + /* testPHP8PseudoTypeFalseAndBool */ + // Intentional fatal error - false pseudotype is not allowed in combination with bool, but that's not the concern of the method. + public bool|FALSE $pseudoTypeFalseAndBool; + + /* testPHP8ObjectAndClass */ + // Intentional fatal error - object is not allowed in combination with class name, but that's not the concern of the method. + public object|ClassName $objectAndClass; + + /* testPHP8PseudoTypeIterableAndArray */ + // Intentional fatal error - iterable pseudotype is not allowed in combination with array or Traversable, but that's not the concern of the method. + public iterable|array|Traversable $pseudoTypeIterableAndArray; + + /* testPHP8DuplicateTypeInUnionWhitespaceAndComment */ + // Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. + public int |string| /*comment*/ INT $duplicateTypeInUnion; + + /* testPHP81Readonly */ + public readonly int $readonly; + + /* testPHP81ReadonlyWithNullableType */ + public readonly ?array $readonlyWithNullableType; + + /* testPHP81ReadonlyWithUnionType */ + public readonly string|int $readonlyWithUnionType; + + /* testPHP81ReadonlyWithUnionTypeWithNull */ + protected ReadOnly string|null $readonlyWithUnionTypeWithNull; + + /* testPHP81OnlyReadonlyWithUnionType */ + readonly string|int $onlyReadonly; + + /* testPHP81OnlyReadonlyWithUnionTypeMultiple */ + readonly \InterfaceA|\Sub\InterfaceB|false + $onlyReadonly; + + /* testPHP81ReadonlyAndStatic */ + readonly private static ?string $readonlyAndStatic; + + /* testPHP81ReadonlyMixedCase */ + public ReadONLY static $readonlyMixedCase; +}; + +$anon = class { + /* testPHP8PropertySingleAttribute */ + #[PropertyWithAttribute] + public string $foo; + + /* testPHP8PropertyMultipleAttributes */ + #[PropertyWithAttribute(foo: 'bar'), MyAttribute] + protected ?int|float $bar; + + /* testPHP8PropertyMultilineAttribute */ + #[ + PropertyWithAttribute(/* comment */ 'baz') + ] + private mixed $baz; +}; + +enum Suit +{ + /* testEnumProperty */ + protected $anonymous; +} + +enum Direction implements ArrayAccess +{ + case Up; + case Down; + + /* testEnumMethodParamNotProperty */ + public function offsetGet($val) { ... } +} + +$anon = class() { + /* testPHP81IntersectionTypes */ + public Foo&Bar $intersectionType; + + /* testPHP81MoreIntersectionTypes */ + public Foo&Bar&Baz $moreIntersectionTypes; + + /* testPHP81IllegalIntersectionTypes */ + // Intentional fatal error - types which are not allowed for intersection type, but that's not the concern of the method. + public int&string $illegalIntersectionType; + + /* testPHP81NullableIntersectionType */ + // Intentional fatal error - nullability is not allowed with intersection type, but that's not the concern of the method. + public ?Foo&Bar $nullableIntersectionType; +}; + +$anon = class() { + /* testPHP82PseudoTypeTrue */ + public true $pseudoTypeTrue; + + /* testPHP82NullablePseudoTypeTrue */ + static protected ?true $pseudoTypeNullableTrue; + + /* testPHP82PseudoTypeTrueInUnion */ + private int|string|true $pseudoTypeTrueInUnion; + + /* testPHP82PseudoTypeFalseAndTrue */ + // Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. + readonly true|FALSE $pseudoTypeFalseAndTrue; +}; + +class WhitespaceAndCommentsInTypes { + /* testUnionTypeWithWhitespaceAndComment */ + public int | /*comment*/ string $hasWhitespaceAndComment; + + /* testIntersectionTypeWithWhitespaceAndComment */ + public \Foo /*comment*/ & Bar $hasWhitespaceAndComment; +} + +trait DNFTypes { + /* testPHP82DNFTypeStatic */ + public static (Foo&\Bar)|bool $propA; + + /* testPHP82DNFTypeReadonlyA */ + protected readonly float|(Partially\Qualified&Traversable) $propB; + + /* testPHP82DNFTypeReadonlyB */ + private readonly (namespace\Foo&Bar)|string $propC; + + /* testPHP82DNFTypeIllegalNullable */ + // Intentional fatal error - nullable operator cannot be combined with DNF. + var ?(A&\Pck\B)|bool $propD; +} + +class WithFinalProperties { + /* testPHP84FinalPublicTypedProp */ + final public string $val1; + /* testPHP84FinalProtectedTypedProp */ + final protected string $val2; + /* testPHP84FinalMiddleTypedProp */ + public final string $val3; + /* testPHP84FinalMiddleStaticTypedProp */ + public final static string $val4; + /* testPHP84FinalLastTypedProp */ + public readonly final string $val5; + /* testPHP84FinalImplicitVisibilityTypedProp */ + final string $val6; + /* testPHP84FinalImplicitVisibilityProp */ + final $val7; + /* testPHP84FinalNullableTypedProp */ + final public ?string $val8; + /* testPHP84FinalComplexTypedProp */ + final public (Foo&\Bar)|bool $val9; +} + +class AsymVisibility { + /* testPHP84AsymPublicSetProperty */ + public(set) mixed $prop1; + /* testPHP84AsymPublicPublicSetProperty */ + public public(set) (A&B)|null $prop2; + /* testPHP84AsymPublicSetPublicProperty */ + public(set) public bool $prop3; + + /* testPHP84AsymProtectedSetProperty */ + protected(set) readonly mixed $prop4; + /* testPHP84AsymPublicProtectedSetProperty */ + public protected(set) string $prop5; + /* testPHP84AsymProtectedSetPublicProperty */ + protected(set) public ?float $prop6; + + /* testPHP84AsymPrivateSetProperty */ + private(set) string|int $prop7; + /* testPHP84AsymProtectedPrivateSetProperty */ + final protected private(set) $prop8; + /* testPHP84AsymPrivateSetPublicProperty */ + private(set) public mixed $prop9; + + /* testPHP84IllegalAsymPublicProtectedSetStaticProperty */ + public protected(set) static mixed $prop10; +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.php new file mode 100644 index 00000000..3c218911 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.php @@ -0,0 +1,1639 @@ + + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMemberProperties method. + * + * @covers \PHP_CodeSniffer\Files\File::getMemberProperties + */ +final class GetMemberPropertiesTest extends AbstractMethodUnitTest +{ + + + /** + * Test the getMemberProperties() method. + * + * @param string $identifier Comment which precedes the test case. + * @param array $expected Expected function output. + * + * @dataProvider dataGetMemberProperties + * + * @return void + */ + public function testGetMemberProperties($identifier, $expected) + { + $variable = $this->getTargetToken($identifier, T_VARIABLE); + $result = self::$phpcsFile->getMemberProperties($variable); + + // Convert offsets to absolute positions in the token stream. + if (isset($expected['type_token']) === true && is_int($expected['type_token']) === true) { + $expected['type_token'] += $variable; + } + + if (isset($expected['type_end_token']) === true && is_int($expected['type_end_token']) === true) { + $expected['type_end_token'] += $variable; + } + + $this->assertSame($expected, $result); + + }//end testGetMemberProperties() + + + /** + * Data provider for the GetMemberProperties test. + * + * Note: the `expected - type_token` and `expected - type_end_token` indexes should + * contain either `false` (no type) or the _offset_ of the type start/end token in + * relation to the `T_VARIABLE` token which is passed to the getMemberProperties() method. + * + * @see testGetMemberProperties() + * + * @return array>> + */ + public static function dataGetMemberProperties() + { + return [ + 'var-modifier' => [ + 'identifier' => '/* testVar */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'var-modifier-and-type' => [ + 'identifier' => '/* testVarType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?int', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'public-modifier' => [ + 'identifier' => '/* testPublic */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'public-modifier-and-type' => [ + 'identifier' => '/* testPublicType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'protected-modifier' => [ + 'identifier' => '/* testProtected */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'protected-modifier-and-type' => [ + 'identifier' => '/* testProtectedType */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'bool', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'private-modifier' => [ + 'identifier' => '/* testPrivate */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'private-modifier-and-type' => [ + 'identifier' => '/* testPrivateType */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'array', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'static-modifier' => [ + 'identifier' => '/* testStatic */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'static-modifier-and-type' => [ + 'identifier' => '/* testStaticType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'static-and-var-modifier' => [ + 'identifier' => '/* testStaticVar */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'var-and-static-modifier' => [ + 'identifier' => '/* testVarStatic */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'public-static-modifiers' => [ + 'identifier' => '/* testPublicStatic */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'protected-static-modifiers' => [ + 'identifier' => '/* testProtectedStatic */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'private-static-modifiers' => [ + 'identifier' => '/* testPrivateStatic */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'no-modifier' => [ + 'identifier' => '/* testNoPrefix */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'public-and-static-modifier-with-docblock' => [ + 'identifier' => '/* testPublicStaticWithDocblock */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'protected-and-static-modifier-with-docblock' => [ + 'identifier' => '/* testProtectedStaticWithDocblock */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'private-and-static-modifier-with-docblock' => [ + 'identifier' => '/* testPrivateStaticWithDocblock */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-simple-type-prop-1' => [ + 'identifier' => '/* testGroupType 1 */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'float', + 'type_token' => -6, + 'type_end_token' => -6, + 'nullable_type' => false, + ], + ], + 'property-group-simple-type-prop-2' => [ + 'identifier' => '/* testGroupType 2 */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'float', + 'type_token' => -13, + 'type_end_token' => -13, + 'nullable_type' => false, + ], + ], + 'property-group-nullable-type-prop-1' => [ + 'identifier' => '/* testGroupNullableType 1 */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?string', + 'type_token' => -6, + 'type_end_token' => -6, + 'nullable_type' => true, + ], + ], + 'property-group-nullable-type-prop-2' => [ + 'identifier' => '/* testGroupNullableType 2 */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?string', + 'type_token' => -17, + 'type_end_token' => -17, + 'nullable_type' => true, + ], + ], + 'property-group-protected-static-prop-1' => [ + 'identifier' => '/* testGroupProtectedStatic 1 */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-protected-static-prop-2' => [ + 'identifier' => '/* testGroupProtectedStatic 2 */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-protected-static-prop-3' => [ + 'identifier' => '/* testGroupProtectedStatic 3 */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-private-prop-1' => [ + 'identifier' => '/* testGroupPrivate 1 */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-private-prop-2' => [ + 'identifier' => '/* testGroupPrivate 2 */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-private-prop-3' => [ + 'identifier' => '/* testGroupPrivate 3 */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-private-prop-4' => [ + 'identifier' => '/* testGroupPrivate 4 */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-private-prop-5' => [ + 'identifier' => '/* testGroupPrivate 5 */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-private-prop-6' => [ + 'identifier' => '/* testGroupPrivate 6 */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-group-private-prop-7' => [ + 'identifier' => '/* testGroupPrivate 7 */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'messy-nullable-type' => [ + 'identifier' => '/* testMessyNullableType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?array', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'fqn-type' => [ + 'identifier' => '/* testNamespaceType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '\MyNamespace\MyClass', + 'type_token' => -5, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'nullable-classname-type' => [ + 'identifier' => '/* testNullableNamespaceType 1 */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?ClassName', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'nullable-namespace-relative-class-type' => [ + 'identifier' => '/* testNullableNamespaceType 2 */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?Folder\ClassName', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'multiline-namespaced-type' => [ + 'identifier' => '/* testMultilineNamespaceType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '\MyNamespace\MyClass\Foo', + 'type_token' => -18, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'property-after-method' => [ + 'identifier' => '/* testPropertyAfterMethod */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'invalid-property-in-interface' => [ + 'identifier' => '/* testInterfaceProperty */', + 'expected' => [], + ], + 'property-in-nested-class-1' => [ + 'identifier' => '/* testNestedProperty 1 */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'property-in-nested-class-2' => [ + 'identifier' => '/* testNestedProperty 2 */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'php8-mixed-type' => [ + 'identifier' => '/* testPHP8MixedTypeHint */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'miXed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-nullable-mixed-type' => [ + 'identifier' => '/* testPHP8MixedTypeHintNullable */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'namespace-operator-type-declaration' => [ + 'identifier' => '/* testNamespaceOperatorTypeHint */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?namespace\Name', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8-union-types-simple' => [ + 'identifier' => '/* testPHP8UnionTypesSimple */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'int|float', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-two-classes' => [ + 'identifier' => '/* testPHP8UnionTypesTwoClasses */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'MyClassA|\Package\MyClassB', + 'type_token' => -7, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-all-base-types' => [ + 'identifier' => '/* testPHP8UnionTypesAllBaseTypes */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'array|bool|int|float|NULL|object|string', + 'type_token' => -14, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-all-pseudo-types' => [ + 'identifier' => '/* testPHP8UnionTypesAllPseudoTypes */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'false|mixed|self|parent|iterable|Resource', + 'type_token' => -12, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-illegal-types' => [ + 'identifier' => '/* testPHP8UnionTypesIllegalTypes */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + // Missing static, but that's OK as not an allowed syntax. + 'type' => 'callable|void', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-nullable' => [ + 'identifier' => '/* testPHP8UnionTypesNullable */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?int|float', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8-union-types-pseudo-type-null' => [ + 'identifier' => '/* testPHP8PseudoTypeNull */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'null', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-pseudo-type-false' => [ + 'identifier' => '/* testPHP8PseudoTypeFalse */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'false', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-pseudo-type-false-and-bool' => [ + 'identifier' => '/* testPHP8PseudoTypeFalseAndBool */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'bool|FALSE', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-object-and-class' => [ + 'identifier' => '/* testPHP8ObjectAndClass */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'object|ClassName', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-pseudo-type-iterable-and-array' => [ + 'identifier' => '/* testPHP8PseudoTypeIterableAndArray */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'iterable|array|Traversable', + 'type_token' => -6, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-union-types-duplicate-type-with-whitespace-and-comments' => [ + 'identifier' => '/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'int|string|INT', + 'type_token' => -10, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property' => [ + 'identifier' => '/* testPHP81Readonly */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'int', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-nullable-type' => [ + 'identifier' => '/* testPHP81ReadonlyWithNullableType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '?array', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.1-readonly-property-with-union-type' => [ + 'identifier' => '/* testPHP81ReadonlyWithUnionType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'string|int', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-union-type-with-null' => [ + 'identifier' => '/* testPHP81ReadonlyWithUnionTypeWithNull */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'string|null', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-union-type-no-visibility' => [ + 'identifier' => '/* testPHP81OnlyReadonlyWithUnionType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'string|int', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-multi-union-type-no-visibility' => [ + 'identifier' => '/* testPHP81OnlyReadonlyWithUnionTypeMultiple */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '\InterfaceA|\Sub\InterfaceB|false', + 'type_token' => -11, + 'type_end_token' => -3, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-and-static-property' => [ + 'identifier' => '/* testPHP81ReadonlyAndStatic */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '?string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.1-readonly-mixed-case-keyword' => [ + 'identifier' => '/* testPHP81ReadonlyMixedCase */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'php8-property-with-single-attribute' => [ + 'identifier' => '/* testPHP8PropertySingleAttribute */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8-property-with-multiple-attributes' => [ + 'identifier' => '/* testPHP8PropertyMultipleAttributes */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?int|float', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8-property-with-multiline-attribute' => [ + 'identifier' => '/* testPHP8PropertyMultilineAttribute */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'invalid-property-in-enum' => [ + 'identifier' => '/* testEnumProperty */', + 'expected' => [], + ], + 'php8.1-single-intersection-type' => [ + 'identifier' => '/* testPHP81IntersectionTypes */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'Foo&Bar', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-multi-intersection-type' => [ + 'identifier' => '/* testPHP81MoreIntersectionTypes */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'Foo&Bar&Baz', + 'type_token' => -6, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-illegal-intersection-type' => [ + 'identifier' => '/* testPHP81IllegalIntersectionTypes */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'int&string', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-nullable-intersection-type' => [ + 'identifier' => '/* testPHP81NullableIntersectionType */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?Foo&Bar', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + + 'php8.0-union-type-with-whitespace-and-comment' => [ + 'identifier' => '/* testUnionTypeWithWhitespaceAndComment */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'int|string', + 'type_token' => -8, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-intersection-type-with-whitespace-and-comment' => [ + 'identifier' => '/* testIntersectionTypeWithWhitespaceAndComment */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '\Foo&Bar', + 'type_token' => -9, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-true' => [ + 'identifier' => '/* testPHP82PseudoTypeTrue */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'true', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-true-nullable' => [ + 'identifier' => '/* testPHP82NullablePseudoTypeTrue */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?true', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.2-pseudo-type-true-in-union' => [ + 'identifier' => '/* testPHP82PseudoTypeTrueInUnion */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'int|string|true', + 'type_token' => -6, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-invalid-true-false-union' => [ + 'identifier' => '/* testPHP82PseudoTypeFalseAndTrue */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'true|FALSE', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + + 'php8.2-dnf-with-static' => [ + 'identifier' => '/* testPHP82DNFTypeStatic */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '(Foo&\Bar)|bool', + 'type_token' => -9, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-dnf-with-readonly-1' => [ + 'identifier' => '/* testPHP82DNFTypeReadonlyA */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'float|(Partially\Qualified&Traversable)', + 'type_token' => -10, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-dnf-with-readonly-2' => [ + 'identifier' => '/* testPHP82DNFTypeReadonlyB */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '(namespace\Foo&Bar)|string', + 'type_token' => -10, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-dnf-with-illegal-nullable' => [ + 'identifier' => '/* testPHP82DNFTypeIllegalNullable */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?(A&\Pck\B)|bool', + 'type_token' => -11, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.4-final-public-property' => [ + 'identifier' => '/* testPHP84FinalPublicTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-protected-property' => [ + 'identifier' => '/* testPHP84FinalProtectedTypedProp */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-middle-keyword-property' => [ + 'identifier' => '/* testPHP84FinalMiddleTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-middle-keyword-static-property' => [ + 'identifier' => '/* testPHP84FinalMiddleStaticTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-last-keyword-property' => [ + 'identifier' => '/* testPHP84FinalLastTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-implicit-public-typed-property' => [ + 'identifier' => '/* testPHP84FinalImplicitVisibilityTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-implicit-public-untyped-property' => [ + 'identifier' => '/* testPHP84FinalImplicitVisibilityProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'php8.4-final-public-nullable-typed-property' => [ + 'identifier' => '/* testPHP84FinalNullableTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '?string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.4-final-public-complex-type-property' => [ + 'identifier' => '/* testPHP84FinalComplexTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '(Foo&\Bar)|bool', + 'type_token' => -9, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + + 'php8.4-asym-public-set' => [ + 'identifier' => '/* testPHP84AsymPublicSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => 'public', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-public-public-set-dnf-type' => [ + 'identifier' => '/* testPHP84AsymPublicPublicSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'public', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '(A&B)|null', + 'type_token' => -8, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-public-set-public' => [ + 'identifier' => '/* testPHP84AsymPublicSetPublicProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'public', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'bool', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-protected-set-readonly' => [ + 'identifier' => '/* testPHP84AsymProtectedSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => 'protected', + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-public-protected-set' => [ + 'identifier' => '/* testPHP84AsymPublicProtectedSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'protected', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-protected-set-public-nullable-type' => [ + 'identifier' => '/* testPHP84AsymProtectedSetPublicProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'protected', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?float', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.4-asym-private-set-union-type' => [ + 'identifier' => '/* testPHP84AsymPrivateSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => 'private', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'string|int', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-final-protected-private-set' => [ + 'identifier' => '/* testPHP84AsymProtectedPrivateSetProperty */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => 'private', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-private-set-public' => [ + 'identifier' => '/* testPHP84AsymPrivateSetPublicProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'private', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-illegal-asym-public-protected-set-static' => [ + 'identifier' => '/* testPHP84IllegalAsymPublicProtectedSetStaticProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'protected', + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + ]; + + }//end dataGetMemberProperties() + + + /** + * Test receiving an expected exception when a non property is passed. + * + * @param string $identifier Comment which precedes the test case. + * + * @dataProvider dataNotClassProperty + * + * @return void + */ + public function testNotClassPropertyException($identifier) + { + $this->expectRunTimeException('$stackPtr is not a class member var'); + + $variable = $this->getTargetToken($identifier, T_VARIABLE); + self::$phpcsFile->getMemberProperties($variable); + + }//end testNotClassPropertyException() + + + /** + * Data provider for the NotClassPropertyException test. + * + * @see testNotClassPropertyException() + * + * @return array> + */ + public static function dataNotClassProperty() + { + return [ + 'method parameter' => ['/* testMethodParam */'], + 'variable import using global keyword' => ['/* testImportedGlobal */'], + 'function local variable' => ['/* testLocalVariable */'], + 'global variable' => ['/* testGlobalVariable */'], + 'method parameter in anon class nested in ternary' => ['/* testNestedMethodParam 1 */'], + 'method parameter in anon class nested in function call' => ['/* testNestedMethodParam 2 */'], + 'method parameter in enum' => ['/* testEnumMethodParamNotProperty */'], + ]; + + }//end dataNotClassProperty() + + + /** + * Test receiving an expected exception when a non variable is passed. + * + * @return void + */ + public function testNotAVariableException() + { + $this->expectRunTimeException('$stackPtr must be of type T_VARIABLE'); + + $next = $this->getTargetToken('/* testNotAVariable */', T_RETURN); + self::$phpcsFile->getMemberProperties($next); + + }//end testNotAVariableException() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError1Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError1Test.inc new file mode 100644 index 00000000..465679eb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError1Test.inc @@ -0,0 +1,4 @@ + + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodParameters + */ +final class GetMethodParametersParseError1Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an empty array when encountering a specific parse error. + * + * @return void + */ + public function testParseError() + { + $target = $this->getTargetToken('/* testParseError */', [T_FUNCTION, T_CLOSURE, T_FN]); + $result = self::$phpcsFile->getMethodParameters($target); + + $this->assertSame([], $result); + + }//end testParseError() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError2Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError2Test.inc new file mode 100644 index 00000000..667cb5ed --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError2Test.inc @@ -0,0 +1,4 @@ + + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodParameters + */ +final class GetMethodParametersParseError2Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an empty array when encountering a specific parse error. + * + * @return void + */ + public function testParseError() + { + $target = $this->getTargetToken('/* testParseError */', [T_FUNCTION, T_CLOSURE, T_FN]); + $result = self::$phpcsFile->getMethodParameters($target); + + $this->assertSame([], $result); + + }//end testParseError() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.inc new file mode 100644 index 00000000..3a12adea --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.inc @@ -0,0 +1,352 @@ + $b; + +/* testArrowFunctionReturnByRef */ +fn&(?string $a) => $b; + +/* testArrayDefaultValues */ +function arrayDefaultValues($var1 = [], $var2 = array(1, 2, 3) ) {} + +/* testConstantDefaultValueSecondParam */ +function constantDefaultValueSecondParam($var1, $var2 = M_PI) {} + +/* testScalarTernaryExpressionInDefault */ +function ternayInDefault( $a = FOO ? 'bar' : 10, ? bool $b ) {} + +/* testVariadicFunction */ +function variadicFunction( int ... $a ) {} + +/* testVariadicByRefFunction */ +function variadicByRefFunction( &...$a ) {} + +/* testVariadicFunctionClassType */ +function variableLengthArgument($unit, DateInterval ...$intervals) {} + +/* testNameSpacedTypeDeclaration */ +function namespacedClassType( \Package\Sub\ClassName $a, ?Sub\AnotherClass $b ) {} + +/* testWithAllTypes */ +class testAllTypes { + function allTypes( + ?ClassName $a, + self $b, + parent $c, + object $d, + ?int $e, + string &$f, + iterable $g, + bool $h = true, + callable $i = 'is_null', + float $j = 1.1, + array ...$k + ) {} +} + +/* testArrowFunctionWithAllTypes */ +$fn = fn( + ?ClassName $a, + self $b, + parent $c, + object $d, + ?int $e, + string &$f, + iterable $g, + bool $h = true, + callable $i = 'is_null', + float $j = 1.1, + array ...$k +) => $something; + +/* testMessyDeclaration */ +function messyDeclaration( + // comment + ?\MyNS /* comment */ + \ SubCat // phpcs:ignore Standard.Cat.Sniff -- for reasons. + \ MyClass $a, + $b /* comment */ = /* comment */ 'default' /* comment*/, + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + ? /*comment*/ + bool // phpcs:disable Stnd.Cat.Sniff -- For reasons. + & /*test*/ ... /* phpcs:ignore */ $c +) {} + +/* testPHP8MixedTypeHint */ +function mixedTypeHint(mixed &...$var1) {} + +/* testPHP8MixedTypeHintNullable */ +// Intentional fatal error - nullability is not allowed with mixed, but that's not the concern of the method. +function mixedTypeHintNullable(?Mixed $var1) {} + +/* testNamespaceOperatorTypeHint */ +function namespaceOperatorTypeHint(?namespace\Name $var1) {} + +/* testPHP8UnionTypesSimple */ +function unionTypeSimple(int|float $number, self|parent &...$obj) {} + +/* testPHP8UnionTypesWithSpreadOperatorAndReference */ +function globalFunctionWithSpreadAndReference(float|null &$paramA, string|int ...$paramB ) {} + +/* testPHP8UnionTypesSimpleWithBitwiseOrInDefault */ +$fn = fn(int|float $var = CONSTANT_A | CONSTANT_B) => $var; + +/* testPHP8UnionTypesTwoClasses */ +function unionTypesTwoClasses(MyClassA|\Package\MyClassB $var) {} + +/* testPHP8UnionTypesAllBaseTypes */ +function unionTypesAllBaseTypes(array|bool|callable|int|float|null|object|string $var) {} + +/* testPHP8UnionTypesAllPseudoTypes */ +// Intentional fatal error - mixing types which cannot be combined, but that's not the concern of the method. +function unionTypesAllPseudoTypes(false|mixed|self|parent|iterable|Resource $var) {} + +/* testPHP8UnionTypesNullable */ +// Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. +$closure = function (?int|float $number) {}; + +/* testPHP8PseudoTypeNull */ +// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeNull(null $var = null) {} + +/* testPHP8PseudoTypeFalse */ +// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeFalse(false $var = false) {} + +/* testPHP8PseudoTypeFalseAndBool */ +// Intentional fatal error - false pseudotype is not allowed in combination with bool, but that's not the concern of the method. +function pseudoTypeFalseAndBool(bool|false $var = false) {} + +/* testPHP8ObjectAndClass */ +// Intentional fatal error - object is not allowed in combination with class name, but that's not the concern of the method. +function objectAndClass(object|ClassName $var) {} + +/* testPHP8PseudoTypeIterableAndArray */ +// Intentional fatal error - iterable pseudotype is not allowed in combination with array or Traversable, but that's not the concern of the method. +function pseudoTypeIterableAndArray(iterable|array|Traversable $var) {} + +/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */ +// Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. +function duplicateTypeInUnion( int | string /*comment*/ | INT $var) {} + +class ConstructorPropertyPromotionNoTypes { + /* testPHP8ConstructorPropertyPromotionNoTypes */ + public function __construct( + public $x = 0.0, + protected $y = '', + private $z = null, + ) {} +} + +class ConstructorPropertyPromotionWithTypes { + /* testPHP8ConstructorPropertyPromotionWithTypes */ + public function __construct(protected float|int $x, public ?string &$y = 'test', private mixed $z) {} +} + +class ConstructorPropertyPromotionAndNormalParams { + /* testPHP8ConstructorPropertyPromotionAndNormalParam */ + public function __construct(public int $promotedProp, ?int $normalArg) {} +} + +class ConstructorPropertyPromotionWithReadOnly { + /* testPHP81ConstructorPropertyPromotionWithReadOnly */ + public function __construct(public readonly ?int $promotedProp, ReadOnly private string|bool &$promotedToo) {} +} + +class ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration { + /* testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration */ + // Intentional fatal error. Readonly properties MUST be typed. + public function __construct(public readonly $promotedProp, ReadOnly private &$promotedToo) {} +} + +class ConstructorPropertyPromotionWithOnlyReadOnly { + /* testPHP81ConstructorPropertyPromotionWithOnlyReadOnly */ + public function __construct(readonly Foo&Bar $promotedProp, readonly ?bool $promotedToo,) {} +} + +class ConstructorPropertyPromotionWithAsymVisibility { + /* testPHP84ConstructorPropertyPromotionWithAsymVisibility */ + public function __construct( + protected(set) string|Book $book, + public private(set) ?Publisher $publisher, + Private(set) PROTECTED Author $author, + readonly public(set) int $pubYear, + protected(set) $illegalMissingType, + ) {} +} + +/* testPHP8ConstructorPropertyPromotionGlobalFunction */ +// Intentional fatal error. Property promotion not allowed in non-constructor, but that's not the concern of this method. +function globalFunction(private $x) {} + +abstract class ConstructorPropertyPromotionAbstractMethod { + /* testPHP8ConstructorPropertyPromotionAbstractMethod */ + // Intentional fatal error. + // 1. Property promotion not allowed in abstract method, but that's not the concern of this method. + // 2. Variadic arguments not allowed in property promotion, but that's not the concern of this method. + // 3. The callable type is not supported for properties, but that's not the concern of this method. + abstract public function __construct(public callable $y, private ...$x); +} + +/* testCommentsInParameter */ +function commentsInParams( + // Leading comment. + ?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ 'default value' . /*-*/ 'second part' // Trailing comment. +) {} + +/* testParameterAttributesInFunctionDeclaration */ +class ParametersWithAttributes( + public function __construct( + #[\MyExample\MyAttribute] private string $constructorPropPromTypedParamSingleAttribute, + #[MyAttr([1, 2])] + Type|false + $typedParamSingleAttribute, + #[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute, + #[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes, + #[MyAttribute(array("key" => "value"))] + &...$otherParam, + ) {} +} + +/* testPHP8IntersectionTypes */ +function intersectionTypes(Foo&Bar $obj1, Boo&Bar $obj2) {} + +/* testPHP81IntersectionTypesWithSpreadOperatorAndReference */ +function globalFunctionWithSpreadAndReference(Boo&Bar &$paramA, Foo&Bar ...$paramB) {} + +/* testPHP81MoreIntersectionTypes */ +function moreIntersectionTypes(MyClassA&\Package\MyClassB&\Package\MyClassC $var) {} + +/* testPHP81IllegalIntersectionTypes */ +// Intentional fatal error - simple types are not allowed with intersection types, but that's not the concern of the method. +$closure = function (string&int $numeric_string) {}; + +/* testPHP81NullableIntersectionTypes */ +// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. +$closure = function (?Foo&Bar $object) {}; + +/* testPHP82PseudoTypeTrue */ +function pseudoTypeTrue(?true $var = true) {} + +/* testPHP82PseudoTypeFalseAndTrue */ +// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. +function pseudoTypeFalseAndTrue(true|false $var = true) {} + +/* testPHP81NewInInitializers */ +function newInInitializers( + TypeA $new = new TypeA(self::CONST_VALUE), + \Package\TypeB $newToo = new \Package\TypeB(10, 'string'), +) {} + +/* testPHP82DNFTypes */ +function dnfTypes( + #[MyAttribute] + false|(Foo&Bar)|true $obj1, + (\Boo&\Pck\Bar)|(Boo&Baz) $obj2 = new Boo() +) {} + +/* testPHP82DNFTypesWithSpreadOperatorAndReference */ +function dnfInGlobalFunctionWithSpreadAndReference((Countable&MeMe)|iterable &$paramA, true|(Foo&Bar) ...$paramB) {} + +/* testPHP82DNFTypesIllegalNullable */ +// Intentional fatal error - nullable operator cannot be combined with DNF. +$dnf_closure = function (? ( MyClassA & /*comment*/ \Package\MyClassB & \Package\MyClassC ) $var): void {}; + +/* testPHP82DNFTypesInArrow */ +$dnf_arrow = fn((Hi&Ho)|FALSE &...$range): string => $a; + +/* testFunctionCallFnPHPCS353-354 */ +$value = $obj->fn(true); + +/* testClosureNoParams */ +function() {}; + +/* testClosure */ +function( $a = 'test' ) {}; + +/* testClosureUseNoParams */ +function() use() {}; + +/* testClosureUse */ +function() use( $foo, $bar ) {}; + +/* testClosureUseWithReference */ +$cl = function() use (&$foo, &$bar) {}; + +/* testFunctionParamListWithTrailingComma */ +function trailingComma( + ?string $foo /*comment*/ , + $bar = 0, +) {} + +/* testClosureParamListWithTrailingComma */ +function( + $foo, + $bar, +) {}; + +/* testArrowFunctionParamListWithTrailingComma */ +$fn = fn( ?int $a , ...$b, ) => $b; + +/* testClosureUseWithTrailingComma */ +function() use( + $foo /*comment*/ , + $bar, +) {}; + +/* testArrowFunctionLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.php new file mode 100644 index 00000000..e660275f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.php @@ -0,0 +1,3347 @@ + + * @author Juliette Reinders Folmer + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodParameters + */ +final class GetMethodParametersTest extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an expected exception when a non function/use token is passed. + * + * @param string $commentString The comment which preceeds the test. + * @param int|string|array $targetTokenType The token type to search for after $commentString. + * + * @dataProvider dataUnexpectedTokenException + * + * @return void + */ + public function testUnexpectedTokenException($commentString, $targetTokenType) + { + $this->expectRunTimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); + + $target = $this->getTargetToken($commentString, $targetTokenType); + self::$phpcsFile->getMethodParameters($target); + + }//end testUnexpectedTokenException() + + + /** + * Data Provider. + * + * @see testUnexpectedTokenException() For the array format. + * + * @return array>> + */ + public static function dataUnexpectedTokenException() + { + return [ + 'interface' => [ + 'commentString' => '/* testNotAFunction */', + 'targetTokenType' => T_INTERFACE, + ], + 'function-call-fn-phpcs-3.5.3-3.5.4' => [ + 'commentString' => '/* testFunctionCallFnPHPCS353-354 */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + 'fn-live-coding' => [ + 'commentString' => '/* testArrowFunctionLiveCoding */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + ]; + + }//end dataUnexpectedTokenException() + + + /** + * Test receiving an expected exception when a non-closure use token is passed. + * + * @param string $identifier The comment which preceeds the test. + * + * @dataProvider dataInvalidUse + * + * @return void + */ + public function testInvalidUse($identifier) + { + $this->expectRunTimeException('$stackPtr was not a valid T_USE'); + + $use = $this->getTargetToken($identifier, [T_USE]); + self::$phpcsFile->getMethodParameters($use); + + }//end testInvalidUse() + + + /** + * Data Provider. + * + * @see testInvalidUse() For the array format. + * + * @return array> + */ + public static function dataInvalidUse() + { + return [ + 'ImportUse' => ['/* testImportUse */'], + 'ImportGroupUse' => ['/* testImportGroupUse */'], + 'TraitUse' => ['/* testTraitUse */'], + ]; + + }//end dataInvalidUse() + + + /** + * Test receiving an empty array when there are no parameters. + * + * @param string $commentString The comment which preceeds the test. + * @param int|string|array $targetTokenType Optional. The token type to search for after $commentString. + * Defaults to the function/closure/arrow tokens. + * + * @dataProvider dataNoParams + * + * @return void + */ + public function testNoParams($commentString, $targetTokenType=[T_FUNCTION, T_CLOSURE, T_FN]) + { + $target = $this->getTargetToken($commentString, $targetTokenType); + $result = self::$phpcsFile->getMethodParameters($target); + + $this->assertSame([], $result); + + }//end testNoParams() + + + /** + * Data Provider. + * + * @see testNoParams() For the array format. + * + * @return array>> + */ + public static function dataNoParams() + { + return [ + 'FunctionNoParams' => [ + 'commentString' => '/* testFunctionNoParams */', + ], + 'ClosureNoParams' => [ + 'commentString' => '/* testClosureNoParams */', + ], + 'ClosureUseNoParams' => [ + 'commentString' => '/* testClosureUseNoParams */', + 'targetTokenType' => T_USE, + ], + ]; + + }//end dataNoParams() + + + /** + * Verify pass-by-reference parsing. + * + * @return void + */ + public function testPassByReference() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 5, + 'name' => '$var', + 'content' => '&$var', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 4, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPassByReference() + + + /** + * Verify array hint parsing. + * + * @return void + */ + public function testArrayHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'array $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'array', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrayHint() + + + /** + * Verify variable. + * + * @return void + */ + public function testVariable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$var', + 'content' => '$var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testVariable() + + + /** + * Verify default value parsing with a single function param. + * + * @return void + */ + public function testSingleDefaultValue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1=self::CONSTANT', + 'default' => 'self::CONSTANT', + 'default_token' => 6, + 'default_equal_token' => 5, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testSingleDefaultValue() + + + /** + * Verify default value parsing. + * + * @return void + */ + public function testDefaultValues() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1=1', + 'default' => '1', + 'default_token' => 6, + 'default_equal_token' => 5, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 7, + ]; + $expected[1] = [ + 'token' => 9, + 'name' => '$var2', + 'content' => "\$var2='value'", + 'default' => "'value'", + 'default_token' => 11, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testDefaultValues() + + + /** + * Verify type hint parsing. + * + * @return void + */ + public function testTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var1', + 'content' => 'foo $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'foo', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => 7, + ]; + + $expected[1] = [ + 'token' => 11, + 'name' => '$var2', + 'content' => 'bar $var2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bar', + 'type_hint_token' => 9, + 'type_hint_end_token' => 9, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testTypeHint() + + + /** + * Verify self type hint parsing. + * + * @return void + */ + public function testSelfTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'self $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testSelfTypeHint() + + + /** + * Verify nullable type hint parsing. + * + * @return void + */ + public function testNullableTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$var1', + 'content' => '?int $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => 8, + ]; + + $expected[1] = [ + 'token' => 14, + 'name' => '$var2', + 'content' => '?\bar $var2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?\bar', + 'type_hint_token' => 11, + 'type_hint_end_token' => 12, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testNullableTypeHint() + + + /** + * Verify "bitwise and" in default value !== pass-by-reference. + * + * @return void + */ + public function testBitwiseAndConstantExpressionDefaultValue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$a', + 'content' => '$a = 10 & 20', + 'default' => '10 & 20', + 'default_token' => 8, + 'default_equal_token' => 6, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testBitwiseAndConstantExpressionDefaultValue() + + + /** + * Verify that arrow functions are supported. + * + * @return void + */ + public function testArrowFunction() + { + // Offsets are relative to the T_FN token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$a', + 'content' => 'int $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 2, + 'type_hint_end_token' => 2, + 'nullable_type' => false, + 'comma_token' => 5, + ]; + + $expected[1] = [ + 'token' => 8, + 'name' => '$b', + 'content' => '...$b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 7, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunction() + + + /** + * Verify that arrow functions are supported. + * + * @return void + */ + public function testArrowFunctionReturnByRef() + { + // Offsets are relative to the T_FN token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$a', + 'content' => '?string $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionReturnByRef() + + + /** + * Verify default value parsing with array values. + * + * @return void + */ + public function testArrayDefaultValues() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1 = []', + 'default' => '[]', + 'default_token' => 8, + 'default_equal_token' => 6, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 12, + 'name' => '$var2', + 'content' => '$var2 = array(1, 2, 3)', + 'default' => 'array(1, 2, 3)', + 'default_token' => 16, + 'default_equal_token' => 14, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrayDefaultValues() + + + /** + * Verify having a T_STRING constant as a default value for the second parameter. + * + * @return void + */ + public function testConstantDefaultValueSecondParam() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, + ]; + $expected[1] = [ + 'token' => 7, + 'name' => '$var2', + 'content' => '$var2 = M_PI', + 'default' => 'M_PI', + 'default_token' => 11, + 'default_equal_token' => 9, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testConstantDefaultValueSecondParam() + + + /** + * Verify distinquishing between a nullable type and a ternary within a default expression. + * + * @return void + */ + public function testScalarTernaryExpressionInDefault() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 5, + 'name' => '$a', + 'content' => '$a = FOO ? \'bar\' : 10', + 'default' => 'FOO ? \'bar\' : 10', + 'default_token' => 9, + 'default_equal_token' => 7, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 18, + ]; + $expected[1] = [ + 'token' => 24, + 'name' => '$b', + 'content' => '? bool $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?bool', + 'type_hint_token' => 22, + 'type_hint_end_token' => 22, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testScalarTernaryExpressionInDefault() + + + /** + * Verify a variadic parameter being recognized correctly. + * + * @return void + */ + public function testVariadicFunction() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$a', + 'content' => 'int ... $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 7, + 'type_hint' => 'int', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testVariadicFunction() + + + /** + * Verify a variadic parameter passed by reference being recognized correctly. + * + * @return void + */ + public function testVariadicByRefFunction() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$a', + 'content' => '&...$a', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 5, + 'variable_length' => true, + 'variadic_token' => 6, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testVariadicByRefFunction() + + + /** + * Verify handling of a variadic parameter with a class based type declaration. + * + * @return void + */ + public function testVariadicFunctionClassType() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$unit', + 'content' => '$unit', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, + ]; + $expected[1] = [ + 'token' => 10, + 'name' => '$intervals', + 'content' => 'DateInterval ...$intervals', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 9, + 'type_hint' => 'DateInterval', + 'type_hint_token' => 7, + 'type_hint_end_token' => 7, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testVariadicFunctionClassType() + + + /** + * Verify distinquishing between a nullable type and a ternary within a default expression. + * + * @return void + */ + public function testNameSpacedTypeDeclaration() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 12, + 'name' => '$a', + 'content' => '\Package\Sub\ClassName $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '\Package\Sub\ClassName', + 'type_hint_token' => 5, + 'type_hint_end_token' => 10, + 'nullable_type' => false, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 20, + 'name' => '$b', + 'content' => '?Sub\AnotherClass $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Sub\AnotherClass', + 'type_hint_token' => 16, + 'type_hint_end_token' => 18, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testNameSpacedTypeDeclaration() + + + /** + * Verify correctly recognizing all type declarations supported by PHP. + * + * @return void + */ + public function testWithAllTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$a', + 'content' => '?ClassName $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?ClassName', + 'type_hint_token' => 7, + 'type_hint_end_token' => 7, + 'nullable_type' => true, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 15, + 'name' => '$b', + 'content' => 'self $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 13, + 'type_hint_end_token' => 13, + 'nullable_type' => false, + 'comma_token' => 16, + ]; + $expected[2] = [ + 'token' => 21, + 'name' => '$c', + 'content' => 'parent $c', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'parent', + 'type_hint_token' => 19, + 'type_hint_end_token' => 19, + 'nullable_type' => false, + 'comma_token' => 22, + ]; + $expected[3] = [ + 'token' => 27, + 'name' => '$d', + 'content' => 'object $d', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object', + 'type_hint_token' => 25, + 'type_hint_end_token' => 25, + 'nullable_type' => false, + 'comma_token' => 28, + ]; + $expected[4] = [ + 'token' => 34, + 'name' => '$e', + 'content' => '?int $e', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 32, + 'type_hint_end_token' => 32, + 'nullable_type' => true, + 'comma_token' => 35, + ]; + $expected[5] = [ + 'token' => 41, + 'name' => '$f', + 'content' => 'string &$f', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 40, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 38, + 'type_hint_end_token' => 38, + 'nullable_type' => false, + 'comma_token' => 42, + ]; + $expected[6] = [ + 'token' => 47, + 'name' => '$g', + 'content' => 'iterable $g', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable', + 'type_hint_token' => 45, + 'type_hint_end_token' => 45, + 'nullable_type' => false, + 'comma_token' => 48, + ]; + $expected[7] = [ + 'token' => 53, + 'name' => '$h', + 'content' => 'bool $h = true', + 'default' => 'true', + 'default_token' => 57, + 'default_equal_token' => 55, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool', + 'type_hint_token' => 51, + 'type_hint_end_token' => 51, + 'nullable_type' => false, + 'comma_token' => 58, + ]; + $expected[8] = [ + 'token' => 63, + 'name' => '$i', + 'content' => 'callable $i = \'is_null\'', + 'default' => "'is_null'", + 'default_token' => 67, + 'default_equal_token' => 65, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 61, + 'type_hint_end_token' => 61, + 'nullable_type' => false, + 'comma_token' => 68, + ]; + $expected[9] = [ + 'token' => 73, + 'name' => '$j', + 'content' => 'float $j = 1.1', + 'default' => '1.1', + 'default_token' => 77, + 'default_equal_token' => 75, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float', + 'type_hint_token' => 71, + 'type_hint_end_token' => 71, + 'nullable_type' => false, + 'comma_token' => 78, + ]; + $expected[10] = [ + 'token' => 84, + 'name' => '$k', + 'content' => 'array ...$k', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 83, + 'type_hint' => 'array', + 'type_hint_token' => 81, + 'type_hint_end_token' => 81, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testWithAllTypes() + + + /** + * Verify correctly recognizing all type declarations supported by PHP when used with an arrow function. + * + * @return void + */ + public function testArrowFunctionWithAllTypes() + { + // Offsets are relative to the T_FN token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$a', + 'content' => '?ClassName $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?ClassName', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => 8, + ]; + $expected[1] = [ + 'token' => 13, + 'name' => '$b', + 'content' => 'self $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 11, + 'type_hint_end_token' => 11, + 'nullable_type' => false, + 'comma_token' => 14, + ]; + $expected[2] = [ + 'token' => 19, + 'name' => '$c', + 'content' => 'parent $c', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'parent', + 'type_hint_token' => 17, + 'type_hint_end_token' => 17, + 'nullable_type' => false, + 'comma_token' => 20, + ]; + $expected[3] = [ + 'token' => 25, + 'name' => '$d', + 'content' => 'object $d', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object', + 'type_hint_token' => 23, + 'type_hint_end_token' => 23, + 'nullable_type' => false, + 'comma_token' => 26, + ]; + $expected[4] = [ + 'token' => 32, + 'name' => '$e', + 'content' => '?int $e', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 30, + 'type_hint_end_token' => 30, + 'nullable_type' => true, + 'comma_token' => 33, + ]; + $expected[5] = [ + 'token' => 39, + 'name' => '$f', + 'content' => 'string &$f', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 38, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 36, + 'type_hint_end_token' => 36, + 'nullable_type' => false, + 'comma_token' => 40, + ]; + $expected[6] = [ + 'token' => 45, + 'name' => '$g', + 'content' => 'iterable $g', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable', + 'type_hint_token' => 43, + 'type_hint_end_token' => 43, + 'nullable_type' => false, + 'comma_token' => 46, + ]; + $expected[7] = [ + 'token' => 51, + 'name' => '$h', + 'content' => 'bool $h = true', + 'default' => 'true', + 'default_token' => 55, + 'default_equal_token' => 53, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool', + 'type_hint_token' => 49, + 'type_hint_end_token' => 49, + 'nullable_type' => false, + 'comma_token' => 56, + ]; + $expected[8] = [ + 'token' => 61, + 'name' => '$i', + 'content' => 'callable $i = \'is_null\'', + 'default' => "'is_null'", + 'default_token' => 65, + 'default_equal_token' => 63, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 59, + 'type_hint_end_token' => 59, + 'nullable_type' => false, + 'comma_token' => 66, + ]; + $expected[9] = [ + 'token' => 71, + 'name' => '$j', + 'content' => 'float $j = 1.1', + 'default' => '1.1', + 'default_token' => 75, + 'default_equal_token' => 73, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float', + 'type_hint_token' => 69, + 'type_hint_end_token' => 69, + 'nullable_type' => false, + 'comma_token' => 76, + ]; + $expected[10] = [ + 'token' => 82, + 'name' => '$k', + 'content' => 'array ...$k', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 81, + 'type_hint' => 'array', + 'type_hint_token' => 79, + 'type_hint_end_token' => 79, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionWithAllTypes() + + + /** + * Verify handling of a declaration interlaced with whitespace and comments. + * + * @return void + */ + public function testMessyDeclaration() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 25, + 'name' => '$a', + 'content' => '// comment + ?\MyNS /* comment */ + \ SubCat // phpcs:ignore Standard.Cat.Sniff -- for reasons. + \ MyClass $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?\MyNS\SubCat\MyClass', + 'type_hint_token' => 9, + 'type_hint_end_token' => 23, + 'nullable_type' => true, + 'comma_token' => 26, + ]; + $expected[1] = [ + 'token' => 29, + 'name' => '$b', + 'content' => "\$b /* comment */ = /* comment */ 'default' /* comment*/", + 'default' => "'default' /* comment*/", + 'default_token' => 37, + 'default_equal_token' => 33, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 40, + ]; + $expected[2] = [ + 'token' => 62, + 'name' => '$c', + 'content' => '// phpcs:ignore Stnd.Cat.Sniff -- For reasons. + ? /*comment*/ + bool // phpcs:disable Stnd.Cat.Sniff -- For reasons. + & /*test*/ ... /* phpcs:ignore */ $c', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 54, + 'variable_length' => true, + 'variadic_token' => 58, + 'type_hint' => '?bool', + 'type_hint_token' => 50, + 'type_hint_end_token' => 50, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testMessyDeclaration() + + + /** + * Verify recognition of PHP8 mixed type declaration. + * + * @return void + */ + public function testPHP8MixedTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var1', + 'content' => 'mixed &...$var1', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 6, + 'variable_length' => true, + 'variadic_token' => 7, + 'type_hint' => 'mixed', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8MixedTypeHint() + + + /** + * Verify recognition of PHP8 mixed type declaration with nullability. + * + * @return void + */ + public function testPHP8MixedTypeHintNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$var1', + 'content' => '?Mixed $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Mixed', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8MixedTypeHintNullable() + + + /** + * Verify recognition of type declarations using the namespace operator. + * + * @return void + */ + public function testNamespaceOperatorTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$var1', + 'content' => '?namespace\Name $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?namespace\Name', + 'type_hint_token' => 5, + 'type_hint_end_token' => 7, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testNamespaceOperatorTypeHint() + + + /** + * Verify recognition of PHP8 union type declaration. + * + * @return void + */ + public function testPHP8UnionTypesSimple() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$number', + 'content' => 'int|float $number', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 17, + 'name' => '$obj', + 'content' => 'self|parent &...$obj', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 15, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'self|parent', + 'type_hint_token' => 11, + 'type_hint_end_token' => 13, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesSimple() + + + /** + * Verify recognition of PHP8 union type declaration when the variable has either a spread operator or a reference. + * + * @return void + */ + public function testPHP8UnionTypesWithSpreadOperatorAndReference() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$paramA', + 'content' => 'float|null &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 8, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float|null', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 17, + 'name' => '$paramB', + 'content' => 'string|int ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'string|int', + 'type_hint_token' => 12, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesWithSpreadOperatorAndReference() + + + /** + * Verify recognition of PHP8 union type declaration with a bitwise or in the default value. + * + * @return void + */ + public function testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'int|float $var = CONSTANT_A | CONSTANT_B', + 'default' => 'CONSTANT_A | CONSTANT_B', + 'default_token' => 10, + 'default_equal_token' => 8, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + 'type_hint_token' => 2, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + + + /** + * Verify recognition of PHP8 union type declaration with two classes. + * + * @return void + */ + public function testPHP8UnionTypesTwoClasses() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 11, + 'name' => '$var', + 'content' => 'MyClassA|\Package\MyClassB $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'MyClassA|\Package\MyClassB', + 'type_hint_token' => 4, + 'type_hint_end_token' => 9, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesTwoClasses() + + + /** + * Verify recognition of PHP8 union type declaration with all base types. + * + * @return void + */ + public function testPHP8UnionTypesAllBaseTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 20, + 'name' => '$var', + 'content' => 'array|bool|callable|int|float|null|object|string $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'array|bool|callable|int|float|null|object|string', + 'type_hint_token' => 4, + 'type_hint_end_token' => 18, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesAllBaseTypes() + + + /** + * Verify recognition of PHP8 union type declaration with all pseudo types. + * + * Note: "Resource" is not a type, but seen as a class name. + * + * @return void + */ + public function testPHP8UnionTypesAllPseudoTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 16, + 'name' => '$var', + 'content' => 'false|mixed|self|parent|iterable|Resource $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false|mixed|self|parent|iterable|Resource', + 'type_hint_token' => 4, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesAllPseudoTypes() + + + /** + * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP8UnionTypesNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$number', + 'content' => '?int|float $number', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int|float', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesNullable() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type null. + * + * @return void + */ + public function testPHP8PseudoTypeNull() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'null $var = null', + 'default' => 'null', + 'default_token' => 10, + 'default_equal_token' => 8, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'null', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeNull() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type false. + * + * @return void + */ + public function testPHP8PseudoTypeFalse() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'false $var = false', + 'default' => 'false', + 'default_token' => 10, + 'default_equal_token' => 8, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeFalse() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * + * @return void + */ + public function testPHP8PseudoTypeFalseAndBool() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var', + 'content' => 'bool|false $var = false', + 'default' => 'false', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool|false', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeFalseAndBool() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * + * @return void + */ + public function testPHP8ObjectAndClass() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var', + 'content' => 'object|ClassName $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object|ClassName', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ObjectAndClass() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * + * @return void + */ + public function testPHP8PseudoTypeIterableAndArray() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 10, + 'name' => '$var', + 'content' => 'iterable|array|Traversable $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable|array|Traversable', + 'type_hint_token' => 4, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeIterableAndArray() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * + * @return void + */ + public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 17, + 'name' => '$var', + 'content' => 'int | string /*comment*/ | INT $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|string|INT', + 'type_hint_token' => 5, + 'type_hint_end_token' => 15, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8DuplicateTypeInUnionWhitespaceAndComment() + + + /** + * Verify recognition of PHP8 constructor property promotion without type declaration, with defaults. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionNoTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$x', + 'content' => 'public $x = 0.0', + 'default' => '0.0', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 6, + 'property_readonly' => false, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 18, + 'name' => '$y', + 'content' => 'protected $y = \'\'', + 'default' => "''", + 'default_token' => 22, + 'default_equal_token' => 20, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'protected', + 'visibility_token' => 16, + 'property_readonly' => false, + 'comma_token' => 23, + ]; + $expected[2] = [ + 'token' => 28, + 'name' => '$z', + 'content' => 'private $z = null', + 'default' => 'null', + 'default_token' => 32, + 'default_equal_token' => 30, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 26, + 'property_readonly' => false, + 'comma_token' => 33, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionNoTypes() + + + /** + * Verify recognition of PHP8 constructor property promotion with type declarations. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionWithTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 10, + 'name' => '$x', + 'content' => 'protected float|int $x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float|int', + 'type_hint_token' => 6, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'property_visibility' => 'protected', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => 11, + ]; + $expected[1] = [ + 'token' => 19, + 'name' => '$y', + 'content' => 'public ?string &$y = \'test\'', + 'default' => "'test'", + 'default_token' => 23, + 'default_equal_token' => 21, + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 18, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 16, + 'type_hint_end_token' => 16, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 13, + 'property_readonly' => false, + 'comma_token' => 24, + ]; + $expected[2] = [ + 'token' => 30, + 'name' => '$z', + 'content' => 'private mixed $z', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'mixed', + 'type_hint_token' => 28, + 'type_hint_end_token' => 28, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 26, + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionWithTypes() + + + /** + * Verify recognition of PHP8 constructor with both property promotion as well as normal parameters. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionAndNormalParam() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$promotedProp', + 'content' => 'public int $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 6, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 14, + 'name' => '$normalArg', + 'content' => '?int $normalArg', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 12, + 'type_hint_end_token' => 12, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionAndNormalParam() + + + /** + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword. + * + * @return void + */ + public function testPHP81ConstructorPropertyPromotionWithReadOnly() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 11, + 'name' => '$promotedProp', + 'content' => 'public readonly ?int $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 9, + 'type_hint_end_token' => 9, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => true, + 'readonly_token' => 6, + 'comma_token' => 12, + ]; + $expected[1] = [ + 'token' => 23, + 'name' => '$promotedToo', + 'content' => 'ReadOnly private string|bool &$promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 22, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string|bool', + 'type_hint_token' => 18, + 'type_hint_end_token' => 20, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 16, + 'property_readonly' => true, + 'readonly_token' => 14, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81ConstructorPropertyPromotionWithReadOnly() + + + /** + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword + * without a property type. + * + * @return void + */ + public function testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$promotedProp', + 'content' => 'public readonly $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => true, + 'readonly_token' => 6, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 16, + 'name' => '$promotedToo', + 'content' => 'ReadOnly private &$promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 15, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 13, + 'property_readonly' => true, + 'readonly_token' => 11, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration() + + + /** + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly + * keyword without explicit visibility. + * + * @return void + */ + public function testPHP81ConstructorPropertyPromotionWithOnlyReadOnly() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 10, + 'name' => '$promotedProp', + 'content' => 'readonly Foo&Bar $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 6, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'property_readonly' => true, + 'readonly_token' => 4, + 'comma_token' => 11, + ]; + $expected[1] = [ + 'token' => 18, + 'name' => '$promotedToo', + 'content' => 'readonly ?bool $promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?bool', + 'type_hint_token' => 16, + 'type_hint_end_token' => 16, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'property_readonly' => true, + 'readonly_token' => 13, + 'comma_token' => 19, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81ConstructorPropertyPromotionWithOnlyReadOnly() + + + /** + * Verify recognition of PHP8 constructor with property promotion using PHP 8.4 asymmetric visibility. + * + * @return void + */ + public function testPHP84ConstructorPropertyPromotionWithAsymVisibility() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 12, + 'name' => '$book', + 'content' => 'protected(set) string|Book $book', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string|Book', + 'type_hint_token' => 8, + 'type_hint_end_token' => 10, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'set_visibility' => 'protected(set)', + 'set_visibility_token' => 6, + 'property_readonly' => false, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 23, + 'name' => '$publisher', + 'content' => 'public private(set) ?Publisher $publisher', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Publisher', + 'type_hint_token' => 21, + 'type_hint_end_token' => 21, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 16, + 'set_visibility' => 'private(set)', + 'set_visibility_token' => 18, + 'property_readonly' => false, + 'comma_token' => 24, + ]; + $expected[2] = [ + 'token' => 33, + 'name' => '$author', + 'content' => 'Private(set) PROTECTED Author $author', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Author', + 'type_hint_token' => 31, + 'type_hint_end_token' => 31, + 'nullable_type' => false, + 'property_visibility' => 'PROTECTED', + 'visibility_token' => 29, + 'set_visibility' => 'Private(set)', + 'set_visibility_token' => 27, + 'property_readonly' => false, + 'comma_token' => 34, + ]; + $expected[3] = [ + 'token' => 43, + 'name' => '$pubYear', + 'content' => 'readonly public(set) int $pubYear', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 41, + 'type_hint_end_token' => 41, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'set_visibility' => 'public(set)', + 'set_visibility_token' => 39, + 'property_readonly' => true, + 'readonly_token' => 37, + 'comma_token' => 44, + ]; + $expected[4] = [ + 'token' => 49, + 'name' => '$illegalMissingType', + 'content' => 'protected(set) $illegalMissingType', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'set_visibility' => 'protected(set)', + 'set_visibility_token' => 47, + 'property_readonly' => false, + 'comma_token' => 50, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP84ConstructorPropertyPromotionWithAsymVisibility() + + + /** + * Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionGlobalFunction() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$x', + 'content' => 'private $x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionGlobalFunction() + + + /** + * Verify behaviour when an abstract constructor uses PHP 8 property promotion syntax. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionAbstractMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$y', + 'content' => 'public callable $y', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 6, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 14, + 'name' => '$x', + 'content' => 'private ...$x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 13, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 11, + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionAbstractMethod() + + + /** + * Verify and document behaviour when there are comments within a parameter declaration. + * + * @return void + */ + public function testCommentsInParameter() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 19, + 'name' => '$param', + 'content' => '// Leading comment. + ?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ \'default value\' . /*-*/ \'second part\' // Trailing comment.', + 'default' => '\'default value\' . /*-*/ \'second part\' // Trailing comment.', + 'default_token' => 27, + 'default_equal_token' => 23, + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 13, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => '?MyClass', + 'type_hint_token' => 9, + 'type_hint_end_token' => 9, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testCommentsInParameter() + + + /** + * Verify behaviour when parameters have attributes attached. + * + * @return void + */ + public function testParameterAttributesInFunctionDeclaration() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 17, + 'name' => '$constructorPropPromTypedParamSingleAttribute', + 'content' => '#[\MyExample\MyAttribute] private string $constructorPropPromTypedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 15, + 'type_hint_end_token' => 15, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 13, + 'property_readonly' => false, + 'comma_token' => 18, + ]; + $expected[1] = [ + 'token' => 39, + 'name' => '$typedParamSingleAttribute', + 'content' => '#[MyAttr([1, 2])] + Type|false + $typedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Type|false', + 'type_hint_token' => 34, + 'type_hint_end_token' => 36, + 'nullable_type' => false, + 'comma_token' => 40, + ]; + $expected[2] = [ + 'token' => 59, + 'name' => '$nullableTypedParamMultiAttribute', + 'content' => '#[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 57, + 'type_hint_end_token' => 57, + 'nullable_type' => true, + 'comma_token' => 60, + ]; + $expected[3] = [ + 'token' => 74, + 'name' => '$nonTypedParamTwoAttributes', + 'content' => '#[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 75, + ]; + $expected[4] = [ + 'token' => 95, + 'name' => '$otherParam', + 'content' => '#[MyAttribute(array("key" => "value"))] + &...$otherParam', + 'has_attributes' => true, + 'pass_by_reference' => true, + 'reference_token' => 93, + 'variable_length' => true, + 'variadic_token' => 94, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 96, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testParameterAttributesInFunctionDeclaration() + + + /** + * Verify recognition of PHP8.1 intersection type declaration. + * + * @return void + */ + public function testPHP8IntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$obj1', + 'content' => 'Foo&Bar $obj1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 15, + 'name' => '$obj2', + 'content' => 'Boo&Bar $obj2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 11, + 'type_hint_end_token' => 13, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8IntersectionTypes() + + + /** + * Verify recognition of PHP8.1 intersection type declaration when the variable + * has either a spread operator or a reference. + * + * @return void + */ + public function testPHP81IntersectionTypesWithSpreadOperatorAndReference() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$paramA', + 'content' => 'Boo&Bar &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 8, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 17, + 'name' => '$paramB', + 'content' => 'Foo&Bar ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 12, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81IntersectionTypesWithSpreadOperatorAndReference() + + + /** + * Verify recognition of PHP8.1 intersection type declaration with more types. + * + * @return void + */ + public function testPHP81MoreIntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 16, + 'name' => '$var', + 'content' => 'MyClassA&\Package\MyClassB&\Package\MyClassC $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'type_hint_token' => 4, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81MoreIntersectionTypes() + + + /** + * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. + * + * @return void + */ + public function testPHP81IllegalIntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$numeric_string', + 'content' => 'string&int $numeric_string', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string&int', + 'type_hint_token' => 3, + 'type_hint_end_token' => 5, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81IllegalIntersectionTypes() + + + /** + * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP81NullableIntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$object', + 'content' => '?Foo&Bar $object', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Foo&Bar', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81NullableIntersectionTypes() + + + /** + * Verify recognition of PHP 8.2 stand-alone `true` type. + * + * @return void + */ + public function testPHP82PseudoTypeTrue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$var', + 'content' => '?true $var = true', + 'default' => 'true', + 'default_token' => 11, + 'default_equal_token' => 9, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?true', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82PseudoTypeTrue() + + + /** + * Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true. + * + * @return void + */ + public function testPHP82PseudoTypeFalseAndTrue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var', + 'content' => 'true|false $var = true', + 'default' => 'true', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'true|false', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82PseudoTypeFalseAndTrue() + + + /** + * Verify behaviour when the default value uses the "new" keyword, as is allowed per PHP 8.1. + * + * @return void + */ + public function testPHP81NewInInitializers() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$new', + 'content' => 'TypeA $new = new TypeA(self::CONST_VALUE)', + 'default' => 'new TypeA(self::CONST_VALUE)', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'TypeA', + 'type_hint_token' => 6, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 20, + ]; + $expected[1] = [ + 'token' => 28, + 'name' => '$newToo', + 'content' => '\Package\TypeB $newToo = new \Package\TypeB(10, \'string\')', + 'default' => "new \Package\TypeB(10, 'string')", + 'default_token' => 32, + 'default_equal_token' => 30, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '\Package\TypeB', + 'type_hint_token' => 23, + 'type_hint_end_token' => 26, + 'nullable_type' => false, + 'comma_token' => 44, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81NewInInitializers() + + + /** + * Verify recognition of 8.2 DNF parameter type declarations. + * + * @return void + */ + public function testPHP82DNFTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 21, + 'name' => '$obj1', + 'content' => '#[MyAttribute] + false|(Foo&Bar)|true $obj1', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false|(Foo&Bar)|true', + 'type_hint_token' => 11, + 'type_hint_end_token' => 19, + 'nullable_type' => false, + 'comma_token' => 22, + ]; + $expected[1] = [ + 'token' => 41, + 'name' => '$obj2', + 'content' => '(\Boo&\Pck\Bar)|(Boo&Baz) $obj2 = new Boo()', + 'default' => 'new Boo()', + 'default_token' => 45, + 'default_equal_token' => 43, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '(\Boo&\Pck\Bar)|(Boo&Baz)', + 'type_hint_token' => 25, + 'type_hint_end_token' => 39, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypes() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations when the variable + * has either a spread operator or a reference. + * + * @return void + */ + public function testPHP82DNFTypesWithSpreadOperatorAndReference() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 13, + 'name' => '$paramA', + 'content' => '(Countable&MeMe)|iterable &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 12, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '(Countable&MeMe)|iterable', + 'type_hint_token' => 4, + 'type_hint_end_token' => 10, + 'nullable_type' => false, + 'comma_token' => 14, + ]; + $expected[1] = [ + 'token' => 25, + 'name' => '$paramB', + 'content' => 'true|(Foo&Bar) ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 24, + 'type_hint' => 'true|(Foo&Bar)', + 'type_hint_token' => 16, + 'type_hint_end_token' => 22, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesWithSpreadOperatorAndReference() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations using the nullability operator (not allowed). + * + * @return void + */ + public function testPHP82DNFTypesIllegalNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 27, + 'name' => '$var', + 'content' => '? ( MyClassA & /*comment*/ \Package\MyClassB & \Package\MyClassC ) $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?(MyClassA&\Package\MyClassB&\Package\MyClassC)', + 'type_hint_token' => 5, + 'type_hint_end_token' => 25, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesIllegalNullable() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations in an arrow function. + * + * @return void + */ + public function testPHP82DNFTypesInArrow() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 12, + 'name' => '$range', + 'content' => '(Hi&Ho)|FALSE &...$range', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 10, + 'variable_length' => true, + 'variadic_token' => 11, + 'type_hint' => '(Hi&Ho)|FALSE', + 'type_hint_token' => 2, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesInArrow() + + + /** + * Verify handling of a closure. + * + * @return void + */ + public function testClosure() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 3, + 'name' => '$a', + 'content' => '$a = \'test\'', + 'default' => "'test'", + 'default_token' => 7, + 'default_equal_token' => 5, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosure() + + + /** + * Verify handling of a closure T_USE token correctly. + * + * @return void + */ + public function testClosureUse() + { + // Offsets are relative to the T_USE token. + $expected = []; + $expected[0] = [ + 'token' => 3, + 'name' => '$foo', + 'content' => '$foo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 4, + ]; + $expected[1] = [ + 'token' => 6, + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected, [T_USE]); + + }//end testClosureUse() + + + /** + * Verify handling of a closure T_USE token with variables imported by reference. + * + * @return void + */ + public function testClosureUseWithReference() + { + // Offsets are relative to the T_USE token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$foo', + 'content' => '&$foo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 3, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, + ]; + $expected[1] = [ + 'token' => 8, + 'name' => '$bar', + 'content' => '&$bar', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 7, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected, [T_USE]); + + }//end testClosureUseWithReference() + + + /** + * Verify function declarations with trailing commas are handled correctly. + * + * @return void + */ + public function testFunctionParamListWithTrailingComma() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$foo', + 'content' => '?string $foo /*comment*/', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 7, + 'type_hint_end_token' => 7, + 'nullable_type' => true, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 16, + 'name' => '$bar', + 'content' => '$bar = 0', + 'default' => '0', + 'default_token' => 20, + 'default_equal_token' => 18, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 21, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testFunctionParamListWithTrailingComma() + + + /** + * Verify closure declarations with trailing commas are handled correctly. + * + * @return void + */ + public function testClosureParamListWithTrailingComma() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$foo', + 'content' => '$foo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, + ]; + $expected[1] = [ + 'token' => 8, + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 9, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureParamListWithTrailingComma() + + + /** + * Verify arrow function declarations with trailing commas are handled correctly. + * + * @return void + */ + public function testArrowFunctionParamListWithTrailingComma() + { + // Offsets are relative to the T_FN token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$a', + 'content' => '?int $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => true, + 'comma_token' => 8, + ]; + $expected[1] = [ + 'token' => 11, + 'name' => '$b', + 'content' => '...$b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 10, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 12, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionParamListWithTrailingComma() + + + /** + * Verify closure T_USE statements with trailing commas are handled correctly. + * + * @return void + */ + public function testClosureUseWithTrailingComma() + { + // Offsets are relative to the T_USE token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$foo', + 'content' => '$foo /*comment*/', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 8, + ]; + $expected[1] = [ + 'token' => 11, + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 12, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected, [T_USE]); + + }//end testClosureUseWithTrailingComma() + + + /** + * Test helper. + * + * @param string $commentString The comment which preceeds the test. + * @param array> $expected The expected function output. + * @param int|string|array $targetType Optional. The token type to search for after $marker. + * Defaults to the function/closure/arrow tokens. + * + * @return void + */ + private function getMethodParametersTestHelper($commentString, $expected, $targetType=[T_FUNCTION, T_CLOSURE, T_FN]) + { + $target = $this->getTargetToken($commentString, $targetType); + $found = self::$phpcsFile->getMethodParameters($target); + + // Convert offsets to absolute positions in the token stream. + foreach ($expected as $key => $param) { + $expected[$key]['token'] += $target; + + if (is_int($param['reference_token']) === true) { + $expected[$key]['reference_token'] += $target; + } + + if (is_int($param['variadic_token']) === true) { + $expected[$key]['variadic_token'] += $target; + } + + if (is_int($param['type_hint_token']) === true) { + $expected[$key]['type_hint_token'] += $target; + } + + if (is_int($param['type_hint_end_token']) === true) { + $expected[$key]['type_hint_end_token'] += $target; + } + + if (is_int($param['comma_token']) === true) { + $expected[$key]['comma_token'] += $target; + } + + if (isset($param['default_token']) === true) { + $expected[$key]['default_token'] += $target; + } + + if (isset($param['default_equal_token']) === true) { + $expected[$key]['default_equal_token'] += $target; + } + + if (isset($param['visibility_token']) === true && is_int($param['visibility_token']) === true) { + $expected[$key]['visibility_token'] += $target; + } + + if (isset($param['set_visibility_token']) === true && is_int($param['set_visibility_token']) === true) { + $expected[$key]['set_visibility_token'] += $target; + } + + if (isset($param['readonly_token']) === true) { + $expected[$key]['readonly_token'] += $target; + } + }//end foreach + + $this->assertSame($expected, $found); + + }//end getMethodParametersTestHelper() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.inc new file mode 100644 index 00000000..7f572f66 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.inc @@ -0,0 +1,226 @@ + $number + 1, + $numbers +); + +class ReturnMe { + /* testReturnTypeStatic */ + private function myFunction(): static { + return $this; + } + + /* testReturnTypeNullableStatic */ + function myNullableFunction(): ?static { + return $this; + } +} + +/* testPHP8MixedTypeHint */ +function mixedTypeHint() :mixed {} + +/* testPHP8MixedTypeHintNullable */ +// Intentional fatal error - nullability is not allowed with mixed, but that's not the concern of the method. +function mixedTypeHintNullable(): ?mixed {} + +/* testNamespaceOperatorTypeHint */ +function namespaceOperatorTypeHint() : ?namespace\Name {} + +/* testPHP8UnionTypesSimple */ +function unionTypeSimple($number) : int|float {} + +/* testPHP8UnionTypesTwoClasses */ +$fn = fn($var): MyClassA|\Package\MyClassB => $var; + +/* testPHP8UnionTypesAllBaseTypes */ +function unionTypesAllBaseTypes() : array|bool|callable|int|float|null|Object|string {} + +/* testPHP8UnionTypesAllPseudoTypes */ +// Intentional fatal error - mixing types which cannot be combined, but that's not the concern of the method. +function unionTypesAllPseudoTypes($var) : false|MIXED|self|parent|static|iterable|Resource|void {} + +/* testPHP8UnionTypesNullable */ +// Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. +$closure = function () use($a) :?int|float {}; + +/* testPHP8PseudoTypeNull */ +// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeNull(): null {} + +/* testPHP8PseudoTypeFalse */ +// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeFalse(): false {} + +/* testPHP8PseudoTypeFalseAndBool */ +// Intentional fatal error - false pseudotype is not allowed in combination with bool, but that's not the concern of the method. +function pseudoTypeFalseAndBool(): bool|false {} + +/* testPHP8ObjectAndClass */ +// Intentional fatal error - object is not allowed in combination with class name, but that's not the concern of the method. +function objectAndClass(): object|ClassName {} + +/* testPHP8PseudoTypeIterableAndArray */ +// Intentional fatal error - iterable pseudotype is not allowed in combination with array or Traversable, but that's not the concern of the method. +interface FooBar { + public function pseudoTypeIterableAndArray(): iterable|array|Traversable; +} + +/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */ +// Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. +function duplicateTypeInUnion(): int | /*comment*/ string | INT {} + +/* testPHP81NeverType */ +function never(): never {} + +/* testPHP81NullableNeverType */ +// Intentional fatal error - nullability is not allowed with never, but that's not the concern of the method. +function nullableNever(): ?never {} + +/* testPHP8IntersectionTypes */ +function intersectionTypes(): Foo&Bar {} + +/* testPHP81MoreIntersectionTypes */ +function moreIntersectionTypes(): MyClassA&\Package\MyClassB&\Package\MyClassC {} + +/* testPHP81IntersectionArrowFunction */ +$fn = fn($var): MyClassA&\Package\MyClassB => $var; + +/* testPHP81IllegalIntersectionTypes */ +// Intentional fatal error - simple types are not allowed with intersection types, but that's not the concern of the method. +$closure = function (): string&int {}; + +/* testPHP81NullableIntersectionTypes */ +// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. +$closure = function (): ?Foo&Bar {}; + +/* testPHP82PseudoTypeTrue */ +function pseudoTypeTrue(): ?true {} + +/* testPHP82PseudoTypeFalseAndTrue */ +// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. +function pseudoTypeFalseAndTrue(): true|false {} + +/* testPHP82DNFType */ +function hasDNFType() : bool|(Foo&Bar)|string {} + +abstract class AbstractClass { + /* testPHP82DNFTypeAbstractMethod */ + abstract protected function abstractMethodDNFType() : float|(Foo&Bar); +} + +/* testPHP82DNFTypeIllegalNullable */ +// Intentional fatal error - nullable operator cannot be combined with DNF. +function illegalNullableDNF(): ?(A&\Pck\B)|bool {} + +/* testPHP82DNFTypeClosure */ +$closure = function() : object|(namespace\Foo&Countable) {}; + +/* testPHP82DNFTypeFn */ +// Intentional fatal error - void type cannot be combined with DNF. +$arrow = fn() : null|(Partially\Qualified&Traversable)|void => do_something(); + +/* testNotAFunction */ +return true; + +/* testPhpcsIssue1264 */ +function foo() : array { + echo $foo; +} + +/* testArrowFunctionArrayReturnValue */ +$fn = fn(): array => [a($a, $b)]; + +/* testArrowFunctionReturnByRef */ +fn&(?string $a) : ?string => $b; + +/* testFunctionCallFnPHPCS353-354 */ +$value = $obj->fn(true); + +/* testFunctionDeclarationNestedInTernaryPHPCS2975 */ +return (!$a ? [ new class { public function b(): c {} } ] : []); + +/* testClosureWithUseNoReturnType */ +$closure = function () use($a) /*comment*/ {}; + +/* testClosureWithUseNoReturnTypeIllegalUseProp */ +$closure = function () use ($this->prop){}; + +/* testClosureWithUseWithReturnType */ +$closure = function () use /*comment*/ ($a): Type {}; + +/* testClosureWithUseMultiParamWithReturnType */ +$closure = function () use ($a, &$b, $c, $d, $e, $f, $g): ?array {}; + +/* testArrowFunctionLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.php new file mode 100644 index 00000000..2b47ebbe --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.php @@ -0,0 +1,1562 @@ + + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodProperties method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodProperties + */ +final class GetMethodPropertiesTest extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an expected exception when a non function token is passed. + * + * @param string $commentString The comment which preceeds the test. + * @param string|int|array $targetTokenType The token type to search for after $commentString. + * + * @dataProvider dataNotAFunctionException + * + * @return void + */ + public function testNotAFunctionException($commentString, $targetTokenType) + { + $this->expectRunTimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); + + $next = $this->getTargetToken($commentString, $targetTokenType); + self::$phpcsFile->getMethodProperties($next); + + }//end testNotAFunctionException() + + + /** + * Data Provider. + * + * @see testNotAFunctionException() For the array format. + * + * @return array>> + */ + public static function dataNotAFunctionException() + { + return [ + 'return' => [ + 'commentString' => '/* testNotAFunction */', + 'targetTokenType' => T_RETURN, + ], + 'function-call-fn-phpcs-3.5.3-3.5.4' => [ + 'commentString' => '/* testFunctionCallFnPHPCS353-354 */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + 'fn-live-coding' => [ + 'commentString' => '/* testArrowFunctionLiveCoding */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + ]; + + }//end dataNotAFunctionException() + + + /** + * Test a basic function. + * + * @return void + */ + public function testBasicFunction() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testBasicFunction() + + + /** + * Test a function with a return type. + * + * @return void + */ + public function testReturnFunction() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 11, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnFunction() + + + /** + * Test a closure used as a function argument. + * + * @return void + */ + public function testNestedClosure() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testNestedClosure() + + + /** + * Test a basic method. + * + * @return void + */ + public function testBasicMethod() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testBasicMethod() + + + /** + * Test a private static method. + * + * @return void + */ + public function testPrivateStaticMethod() + { + $expected = [ + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPrivateStaticMethod() + + + /** + * Test a basic final method. + * + * @return void + */ + public function testFinalMethod() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => true, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testFinalMethod() + + + /** + * Test a protected method with a return type. + * + * @return void + */ + public function testProtectedReturnMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'int', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testProtectedReturnMethod() + + + /** + * Test a public method with a return type. + * + * @return void + */ + public function testPublicReturnMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'array', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPublicReturnMethod() + + + /** + * Test a public method with a nullable return type. + * + * @return void + */ + public function testNullableReturnMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '?array', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testNullableReturnMethod() + + + /** + * Test a public method with a nullable return type. + * + * @return void + */ + public function testMessyNullableReturnMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '?array', + 'return_type_token' => 18, + 'return_type_end_token' => 18, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testMessyNullableReturnMethod() + + + /** + * Test a method with a namespaced return type. + * + * @return void + */ + public function testReturnNamespace() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '\MyNamespace\MyClass', + 'return_type_token' => 7, + 'return_type_end_token' => 10, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnNamespace() + + + /** + * Test a method with a messy namespaced return type. + * + * @return void + */ + public function testReturnMultilineNamespace() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '\MyNamespace\MyClass\Foo', + 'return_type_token' => 7, + 'return_type_end_token' => 23, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnMultilineNamespace() + + + /** + * Test a method with an unqualified named return type. + * + * @return void + */ + public function testReturnUnqualifiedName() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => '?MyClass', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnUnqualifiedName() + + + /** + * Test a method with a partially qualified namespaced return type. + * + * @return void + */ + public function testReturnPartiallyQualifiedName() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Sub\Level\MyClass', + 'return_type_token' => 7, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnPartiallyQualifiedName() + + + /** + * Test a basic abstract method. + * + * @return void + */ + public function testAbstractMethod() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testAbstractMethod() + + + /** + * Test an abstract method with a return type. + * + * @return void + */ + public function testAbstractReturnMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'bool', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testAbstractReturnMethod() + + + /** + * Test a basic interface method. + * + * @return void + */ + public function testInterfaceMethod() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testInterfaceMethod() + + + /** + * Test a static arrow function. + * + * @return void + */ + public function testArrowFunction() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'return_type_token' => 9, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunction() + + + /** + * Test a function with return type "static". + * + * @return void + */ + public function testReturnTypeStatic() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => 'static', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnTypeStatic() + + + /** + * Test a function with return type "?static". + * + * @return void + */ + public function testReturnTypeNullableStatic() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?static', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnTypeNullableStatic() + + + /** + * Test a function with return type "mixed". + * + * @return void + */ + public function testPHP8MixedTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'mixed', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8MixedTypeHint() + + + /** + * Test a function with return type "mixed" and nullability. + * + * @return void + */ + public function testPHP8MixedTypeHintNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?mixed', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8MixedTypeHintNullable() + + + /** + * Test a function with return type using the namespace operator. + * + * @return void + */ + public function testNamespaceOperatorTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?namespace\Name', + 'return_type_token' => 9, + 'return_type_end_token' => 11, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testNamespaceOperatorTypeHint() + + + /** + * Verify recognition of PHP8 union type declaration. + * + * @return void + */ + public function testPHP8UnionTypesSimple() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|float', + 'return_type_token' => 9, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesSimple() + + + /** + * Verify recognition of PHP8 union type declaration with two classes. + * + * @return void + */ + public function testPHP8UnionTypesTwoClasses() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA|\Package\MyClassB', + 'return_type_token' => 6, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesTwoClasses() + + + /** + * Verify recognition of PHP8 union type declaration with all base types. + * + * @return void + */ + public function testPHP8UnionTypesAllBaseTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array|bool|callable|int|float|null|Object|string', + 'return_type_token' => 8, + 'return_type_end_token' => 22, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesAllBaseTypes() + + + /** + * Verify recognition of PHP8 union type declaration with all pseudo types. + * + * Note: "Resource" is not a type, but seen as a class name. + * + * @return void + */ + public function testPHP8UnionTypesAllPseudoTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false|MIXED|self|parent|static|iterable|Resource|void', + 'return_type_token' => 9, + 'return_type_end_token' => 23, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesAllPseudoTypes() + + + /** + * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP8UnionTypesNullable() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?int|float', + 'return_type_token' => 12, + 'return_type_end_token' => 14, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesNullable() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type null. + * + * @return void + */ + public function testPHP8PseudoTypeNull() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'null', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeNull() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type false. + * + * @return void + */ + public function testPHP8PseudoTypeFalse() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeFalse() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * + * @return void + */ + public function testPHP8PseudoTypeFalseAndBool() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'bool|false', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeFalseAndBool() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * + * @return void + */ + public function testPHP8ObjectAndClass() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'object|ClassName', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ObjectAndClass() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * + * @return void + */ + public function testPHP8PseudoTypeIterableAndArray() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'iterable|array|Traversable', + 'return_type_token' => 7, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeIterableAndArray() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * + * @return void + */ + public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|string|INT', + 'return_type_token' => 7, + 'return_type_end_token' => 17, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8DuplicateTypeInUnionWhitespaceAndComment() + + + /** + * Verify recognition of PHP8.1 type "never". + * + * @return void + */ + public function testPHP81NeverType() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'never', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81NeverType() + + + /** + * Verify recognition of PHP8.1 type "never" with (illegal) nullability. + * + * @return void + */ + public function testPHP81NullableNeverType() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?never', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81NullableNeverType() + + + /** + * Verify recognition of PHP8.1 intersection type declaration. + * + * @return void + */ + public function testPHP8IntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Foo&Bar', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8IntersectionTypes() + + + /** + * Verify recognition of PHP8.1 intersection type declaration with more types. + * + * @return void + */ + public function testPHP81MoreIntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'return_type_token' => 7, + 'return_type_end_token' => 17, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81MoreIntersectionTypes() + + + /** + * Verify recognition of PHP8.1 intersection type declaration in arrow function. + * + * @return void + */ + public function testPHP81IntersectionArrowFunction() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB', + 'return_type_token' => 6, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81IntersectionArrowFunction() + + + /** + * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. + * + * @return void + */ + public function testPHP81IllegalIntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'string&int', + 'return_type_token' => 6, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81IllegalIntersectionTypes() + + + /** + * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP81NullableIntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?Foo&Bar', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81NullableIntersectionTypes() + + + /** + * Verify recognition of PHP 8.2 stand-alone `true` type. + * + * @return void + */ + public function testPHP82PseudoTypeTrue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?true', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82PseudoTypeTrue() + + + /** + * Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true. + * + * @return void + */ + public function testPHP82PseudoTypeFalseAndTrue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'true|false', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82PseudoTypeFalseAndTrue() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration. + * + * @return void + */ + public function testPHP82DNFType() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'bool|(Foo&Bar)|string', + 'return_type_token' => 8, + 'return_type_end_token' => 16, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFType() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on an abstract method. + * + * @return void + */ + public function testPHP82DNFTypeAbstractMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'float|(Foo&Bar)', + 'return_type_token' => 8, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeAbstractMethod() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration with illegal nullability. + * + * @return void + */ + public function testPHP82DNFTypeIllegalNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?(A&\Pck\B)|bool', + 'return_type_token' => 8, + 'return_type_end_token' => 17, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeIllegalNullable() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on a closure. + * + * @return void + */ + public function testPHP82DNFTypeClosure() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'object|(namespace\Foo&Countable)', + 'return_type_token' => 6, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeClosure() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on an arrow function. + * + * @return void + */ + public function testPHP82DNFTypeFn() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'null|(Partially\Qualified&Traversable)|void', + 'return_type_token' => 6, + 'return_type_end_token' => 16, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeFn() + + + /** + * Test for incorrect tokenization of array return type declarations in PHPCS < 2.8.0. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/1264 + * + * @return void + */ + public function testPhpcsIssue1264() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPhpcsIssue1264() + + + /** + * Test handling of incorrect tokenization of array return type declarations for arrow functions + * in a very specific code sample in PHPCS < 3.5.4. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2773 + * + * @return void + */ + public function testArrowFunctionArrayReturnValue() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 5, + 'return_type_end_token' => 5, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionArrayReturnValue() + + + /** + * Test handling of an arrow function returning by reference. + * + * @return void + */ + public function testArrowFunctionReturnByRef() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?string', + 'return_type_token' => 12, + 'return_type_end_token' => 12, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionReturnByRef() + + + /** + * Test handling of function declaration nested in a ternary, where the colon for the + * return type was incorrectly tokenized as T_INLINE_ELSE prior to PHPCS 3.5.7. + * + * @return void + */ + public function testFunctionDeclarationNestedInTernaryPHPCS2975() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'c', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testFunctionDeclarationNestedInTernaryPHPCS2975() + + + /** + * Test handling of closure declarations with a use variable import without a return type declaration. + * + * @return void + */ + public function testClosureWithUseNoReturnType() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseNoReturnType() + + + /** + * Test handling of closure declarations with an illegal use variable for a property import (not allowed in PHP) + * without a return type declaration. + * + * @return void + */ + public function testClosureWithUseNoReturnTypeIllegalUseProp() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseNoReturnTypeIllegalUseProp() + + + /** + * Test handling of closure declarations with a use variable import with a return type declaration. + * + * @return void + */ + public function testClosureWithUseWithReturnType() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Type', + 'return_type_token' => 14, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseWithReturnType() + + + /** + * Test handling of closure declarations with a use variable import with a return type declaration. + * + * @return void + */ + public function testClosureWithUseMultiParamWithReturnType() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?array', + 'return_type_token' => 32, + 'return_type_end_token' => 32, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseMultiParamWithReturnType() + + + /** + * Test helper. + * + * @param string $commentString The comment which preceeds the test. + * @param array $expected The expected function output. + * + * @return void + */ + private function getMethodPropertiesTestHelper($commentString, $expected) + { + $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE, T_FN]); + $found = self::$phpcsFile->getMethodProperties($function); + + // Convert offsets to absolute positions in the token stream. + if (is_int($expected['return_type_token']) === true) { + $expected['return_type_token'] += $function; + } + + if (is_int($expected['return_type_end_token']) === true) { + $expected['return_type_end_token'] += $function; + } + + $this->assertSame($expected, $found); + + }//end getMethodPropertiesTestHelper() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.inc new file mode 100644 index 00000000..ace5a9bd --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.inc @@ -0,0 +1,25 @@ + 20; +} + +/* testEchoWithTabs */ +echo 'foo', + 'bar' , + 'baz'; + +/* testEndOfFile */ +echo $foo; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.php new file mode 100644 index 00000000..1adb9467 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.php @@ -0,0 +1,334 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getTokensAsString method. + * + * @covers \PHP_CodeSniffer\Files\File::getTokensAsString + */ +final class GetTokensAsStringTest extends AbstractMethodUnitTest +{ + + + /** + * Test passing a non-existent token pointer. + * + * @return void + */ + public function testNonExistentToken() + { + $this->expectRunTimeException('The $start position for getTokensAsString() must exist in the token stack'); + + self::$phpcsFile->getTokensAsString(100000, 10); + + }//end testNonExistentToken() + + + /** + * Test passing a non integer `$start`, like the result of a failed $phpcsFile->findNext(). + * + * @return void + */ + public function testNonIntegerStart() + { + $this->expectRunTimeException('The $start position for getTokensAsString() must exist in the token stack'); + + self::$phpcsFile->getTokensAsString(false, 10); + + }//end testNonIntegerStart() + + + /** + * Test passing a non integer `$length`. + * + * @return void + */ + public function testNonIntegerLength() + { + $result = self::$phpcsFile->getTokensAsString(10, false); + $this->assertSame('', $result); + + $result = self::$phpcsFile->getTokensAsString(10, 1.5); + $this->assertSame('', $result); + + }//end testNonIntegerLength() + + + /** + * Test passing a zero or negative `$length`. + * + * @return void + */ + public function testLengthEqualToOrLessThanZero() + { + $result = self::$phpcsFile->getTokensAsString(10, -10); + $this->assertSame('', $result); + + $result = self::$phpcsFile->getTokensAsString(10, 0); + $this->assertSame('', $result); + + }//end testLengthEqualToOrLessThanZero() + + + /** + * Test passing a `$length` beyond the end of the file. + * + * @return void + */ + public function testLengthBeyondEndOfFile() + { + $semicolon = $this->getTargetToken('/* testEndOfFile */', T_SEMICOLON); + $result = self::$phpcsFile->getTokensAsString($semicolon, 20); + $this->assertSame( + '; +', + $result + ); + + }//end testLengthBeyondEndOfFile() + + + /** + * Test getting a token set as a string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $startTokenType The type of token(s) to look for for the start of the string. + * @param int $length Token length to get. + * @param string $expected The expected function return value. + * + * @dataProvider dataGetTokensAsString + * + * @return void + */ + public function testGetTokensAsString($testMarker, $startTokenType, $length, $expected) + { + $start = $this->getTargetToken($testMarker, $startTokenType); + $result = self::$phpcsFile->getTokensAsString($start, $length); + $this->assertSame($expected, $result); + + }//end testGetTokensAsString() + + + /** + * Data provider. + * + * @see testGetTokensAsString() For the array format. + * + * @return array> + */ + public static function dataGetTokensAsString() + { + return [ + 'length-0' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 0, + 'expected' => '', + ], + 'length-1' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 1, + 'expected' => '1', + ], + 'length-2' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 2, + 'expected' => '1 ', + ], + 'length-3' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 3, + 'expected' => '1 +', + ], + 'length-4' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 4, + 'expected' => '1 + ', + ], + 'length-5' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 5, + 'expected' => '1 + 2', + ], + 'length-6' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 6, + 'expected' => '1 + 2 ', + ], + 'length-7' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 7, + 'expected' => '1 + 2 +', + ], + 'length-8' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 8, + 'expected' => '1 + 2 + +', + ], + 'length-9' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 9, + 'expected' => '1 + 2 + + ', + ], + 'length-10' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 10, + 'expected' => '1 + 2 + + // Comment. +', + ], + 'length-11' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 11, + 'expected' => '1 + 2 + + // Comment. + ', + ], + 'length-12' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 12, + 'expected' => '1 + 2 + + // Comment. + 3', + ], + 'length-13' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 13, + 'expected' => '1 + 2 + + // Comment. + 3 ', + ], + 'length-14' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 14, + 'expected' => '1 + 2 + + // Comment. + 3 +', + ], + 'length-34' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 34, + 'expected' => '1 + 2 + + // Comment. + 3 + 4 + + 5 + 6 + 7 > 20;', + ], + 'namespace' => [ + 'testMarker' => '/* testNamespace */', + 'startTokenType' => T_NAMESPACE, + 'length' => 8, + 'expected' => 'namespace Foo\Bar\Baz;', + ], + 'use-with-comments' => [ + 'testMarker' => '/* testUseWithComments */', + 'startTokenType' => T_USE, + 'length' => 17, + 'expected' => 'use Foo /*comment*/ \ Bar + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + \ Bah;', + ], + 'echo-with-tabs' => [ + 'testMarker' => '/* testEchoWithTabs */', + 'startTokenType' => T_ECHO, + 'length' => 13, + 'expected' => 'echo \'foo\', + \'bar\' , + \'baz\';', + ], + 'end-of-file' => [ + 'testMarker' => '/* testEndOfFile */', + 'startTokenType' => T_ECHO, + 'length' => 4, + 'expected' => 'echo $foo;', + ], + ]; + + }//end dataGetTokensAsString() + + + /** + * Test getting a token set as a string with the original, non tab-replaced content. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $startTokenType The type of token(s) to look for for the start of the string. + * @param int $length Token length to get. + * @param string $expected The expected function return value. + * + * @dataProvider dataGetOrigContent + * + * @return void + */ + public function testGetOrigContent($testMarker, $startTokenType, $length, $expected) + { + $start = $this->getTargetToken($testMarker, $startTokenType); + $result = self::$phpcsFile->getTokensAsString($start, $length, true); + $this->assertSame($expected, $result); + + }//end testGetOrigContent() + + + /** + * Data provider. + * + * @see testGetOrigContent() For the array format. + * + * @return array> + */ + public static function dataGetOrigContent() + { + return [ + 'use-with-comments' => [ + 'testMarker' => '/* testUseWithComments */', + 'startTokenType' => T_USE, + 'length' => 17, + 'expected' => 'use Foo /*comment*/ \ Bar + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + \ Bah;', + ], + 'echo-with-tabs' => [ + 'testMarker' => '/* testEchoWithTabs */', + 'startTokenType' => T_ECHO, + 'length' => 13, + 'expected' => 'echo \'foo\', + \'bar\' , + \'baz\';', + ], + 'end-of-file' => [ + 'testMarker' => '/* testEndOfFile */', + 'startTokenType' => T_ECHO, + 'length' => 4, + 'expected' => 'echo $foo;', + ], + ]; + + }//end dataGetOrigContent() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.inc new file mode 100644 index 00000000..05af8390 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.inc @@ -0,0 +1,216 @@ + $first, 'b' => $something & $somethingElse ]; + +/* testBitwiseAndF */ +$a = array( 'a' => $first, 'b' => $something & \MyClass::$somethingElse ); + +/* testBitwiseAndG */ +$a = $something & $somethingElse; + +/* testBitwiseAndH */ +function myFunction($a = 10 & 20) {} + +/* testBitwiseAndI */ +$closure = function ($a = MY_CONSTANT & parent::OTHER_CONSTANT) {}; + +/* testFunctionReturnByReference */ +function &myFunction() {} + +/* testFunctionPassByReferenceA */ +function myFunction( &$a ) {} + +/* testFunctionPassByReferenceB */ +function myFunction( $a, &$b ) {} + +/* testFunctionPassByReferenceC */ +$closure = function ( &$a ) {}; + +/* testFunctionPassByReferenceD */ +$closure = function ( $a, &$b ) {}; + +/* testFunctionPassByReferenceE */ +function myFunction(array &$one) {} + +/* testFunctionPassByReferenceF */ +$closure = function (\MyClass &$one) {}; + +/* testFunctionPassByReferenceG */ +$closure = function ($param, &...$moreParams) {}; + +/* testForeachValueByReference */ +foreach( $array as $key => &$value ) {} + +/* testForeachKeyByReference */ +foreach( $array as &$key => $value ) {} + +/* testArrayValueByReferenceA */ +$a = [ 'a' => &$something ]; + +/* testArrayValueByReferenceB */ +$a = [ 'a' => $something, 'b' => &$somethingElse ]; + +/* testArrayValueByReferenceC */ +$a = [ &$something ]; + +/* testArrayValueByReferenceD */ +$a = [ $something, &$somethingElse ]; + +/* testArrayValueByReferenceE */ +$a = array( 'a' => &$something ); + +/* testArrayValueByReferenceF */ +$a = array( 'a' => $something, 'b' => &$somethingElse ); + +/* testArrayValueByReferenceG */ +$a = array( &$something ); + +/* testArrayValueByReferenceH */ +$a = array( $something, &$somethingElse ); + +/* testAssignByReferenceA */ +$b = &$something; + +/* testAssignByReferenceB */ +$b =& $something; + +/* testAssignByReferenceC */ +$b .= &$something; + +/* testAssignByReferenceD */ +$myValue = &$obj->getValue(); + +/* testAssignByReferenceE */ +$collection = &collector(); + +/* testAssignByReferenceF */ +$collection ??= &collector(); + +/* testShortListAssignByReferenceNoKeyA */ +[ + &$a, + /* testShortListAssignByReferenceNoKeyB */ + &$b, + /* testNestedShortListAssignByReferenceNoKey */ + [$c, &$d] +] = $array; + +/* testLongListAssignByReferenceNoKeyA */ +list($a, &$b, list(/* testLongListAssignByReferenceNoKeyB */ &$c, /* testLongListAssignByReferenceNoKeyC */ &$d)) = $array; + +[ + /* testNestedShortListAssignByReferenceWithKeyA */ + 'a' => [&$a, $b], + /* testNestedShortListAssignByReferenceWithKeyB */ + 'b' => [$c, &$d] +] = $array; + + +/* testLongListAssignByReferenceWithKeyA */ +list(get_key()[1] => &$e) = [1, 2, 3]; + +/* testPassByReferenceA */ +functionCall(&$something, $somethingElse); + +/* testPassByReferenceB */ +functionCall($something, &$somethingElse); + +/* testPassByReferenceC */ +functionCall($something, &$this->somethingElse); + +/* testPassByReferenceD */ +functionCall($something, &self::$somethingElse); + +/* testPassByReferenceE */ +functionCall($something, &parent::$somethingElse); + +/* testPassByReferenceF */ +functionCall($something, &static::$somethingElse); + +/* testPassByReferenceG */ +functionCall($something, &SomeClass::$somethingElse); + +/* testPassByReferenceH */ +functionCall(&\SomeClass::$somethingElse); + +/* testPassByReferenceI */ +functionCall($something, &\SomeNS\SomeClass::$somethingElse); + +/* testPassByReferenceJ */ +functionCall($something, &namespace\SomeClass::$somethingElse); + +/* testPassByReferencePartiallyQualifiedName */ +functionCall($something, &Sub\Level\SomeClass::$somethingElse); + +/* testNewByReferenceA */ +$foobar2 = &new Foobar(); + +/* testNewByReferenceB */ +functionCall( $something , &new Foobar() ); + +/* testUseByReference */ +$closure = function() use (&$var){}; + +/* testUseByReferenceWithCommentFirstParam */ +$closure = function() use /*comment*/ (&$value){}; + +/* testUseByReferenceWithCommentSecondParam */ +$closure = function() use /*comment*/ ($varA, &$varB){}; + +/* testArrowFunctionReturnByReference */ +fn&($x) => $x; + +$closure = function ( + /* testBitwiseAndExactParameterA */ + $a = MY_CONSTANT & parent::OTHER_CONSTANT, + /* testPassByReferenceExactParameterB */ + &$b, + /* testPassByReferenceExactParameterC */ + &...$c, + /* testBitwiseAndExactParameterD */ + $d = E_NOTICE & E_STRICT, +) {}; + +// Issue PHPCS#3049. +/* testArrowFunctionPassByReferenceA */ +$fn = fn(array &$one) => 1; + +/* testArrowFunctionPassByReferenceB */ +$fn = fn($param, &...$moreParams) => 1; + +/* testClosureReturnByReference */ +$closure = function &($param) use ($value) {}; + +/* testBitwiseAndArrowFunctionInDefault */ +$fn = fn( $one = E_NOTICE & E_STRICT) => 1; + +/* testIntersectionIsNotReference */ +function intersect(Foo&Bar $param) {} + +/* testDNFTypeIsNotReference */ +$fn = fn((Foo&\Bar)|null /* testParamPassByReference */ &$param) => $param; + +/* testTokenizerIssue1284PHPCSlt280A */ +if ($foo) {} +[&$a, /* testTokenizerIssue1284PHPCSlt280B */ &$b] = $c; + +/* testTokenizerIssue1284PHPCSlt280C */ +if ($foo) {} +[&$a, $b]; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.php new file mode 100644 index 00000000..bd908539 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.php @@ -0,0 +1,396 @@ + + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::isReference method. + * + * @covers \PHP_CodeSniffer\Files\File::isReference + */ +final class IsReferenceTest extends AbstractMethodUnitTest +{ + + + /** + * Test that false is returned when a non-"bitwise and" token is passed. + * + * @param string $testMarker Comment which precedes the test case. + * @param array $targetTokens Type of tokens to look for. + * + * @dataProvider dataNotBitwiseAndToken + * + * @return void + */ + public function testNotBitwiseAndToken($testMarker, $targetTokens) + { + $targetTokens[] = T_BITWISE_AND; + + $target = $this->getTargetToken($testMarker, $targetTokens); + $this->assertFalse(self::$phpcsFile->isReference($target)); + + }//end testNotBitwiseAndToken() + + + /** + * Data provider. + * + * @see testNotBitwiseAndToken() + * + * @return array>> + */ + public static function dataNotBitwiseAndToken() + { + return [ + 'Not ampersand token at all' => [ + 'testMarker' => '/* testBitwiseAndA */', + 'targetTokens' => [T_STRING], + ], + 'ampersand in intersection type' => [ + 'testMarker' => '/* testIntersectionIsNotReference */', + 'targetTokens' => [T_TYPE_INTERSECTION], + ], + 'ampersand in DNF type' => [ + 'testMarker' => '/* testDNFTypeIsNotReference */', + 'targetTokens' => [T_TYPE_INTERSECTION], + ], + ]; + + }//end dataNotBitwiseAndToken() + + + /** + * Test correctly identifying whether a "bitwise and" token is a reference or not. + * + * @param string $testMarker Comment which precedes the test case. + * @param bool $expected Expected function output. + * + * @dataProvider dataIsReference + * + * @return void + */ + public function testIsReference($testMarker, $expected) + { + $bitwiseAnd = $this->getTargetToken($testMarker, T_BITWISE_AND); + $result = self::$phpcsFile->isReference($bitwiseAnd); + $this->assertSame($expected, $result); + + }//end testIsReference() + + + /** + * Data provider for the IsReference test. + * + * @see testIsReference() + * + * @return array> + */ + public static function dataIsReference() + { + return [ + 'issue-1971-list-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271A */', + 'expected' => true, + ], + 'issue-1971-list-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271B */', + 'expected' => true, + ], + 'bitwise and: param in function call' => [ + 'testMarker' => '/* testBitwiseAndA */', + 'expected' => false, + ], + 'bitwise and: in unkeyed short array, first value' => [ + 'testMarker' => '/* testBitwiseAndB */', + 'expected' => false, + ], + 'bitwise and: in unkeyed short array, last value' => [ + 'testMarker' => '/* testBitwiseAndC */', + 'expected' => false, + ], + 'bitwise and: in unkeyed long array, last value' => [ + 'testMarker' => '/* testBitwiseAndD */', + 'expected' => false, + ], + 'bitwise and: in keyed short array, last value' => [ + 'testMarker' => '/* testBitwiseAndE */', + 'expected' => false, + ], + 'bitwise and: in keyed long array, last value' => [ + 'testMarker' => '/* testBitwiseAndF */', + 'expected' => false, + ], + 'bitwise and: in assignment' => [ + 'testMarker' => '/* testBitwiseAndG */', + 'expected' => false, + ], + 'bitwise and: in param default value in function declaration' => [ + 'testMarker' => '/* testBitwiseAndH */', + 'expected' => false, + ], + 'bitwise and: in param default value in closure declaration' => [ + 'testMarker' => '/* testBitwiseAndI */', + 'expected' => false, + ], + 'reference: function declared to return by reference' => [ + 'testMarker' => '/* testFunctionReturnByReference */', + 'expected' => true, + ], + 'reference: only param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceA */', + 'expected' => true, + ], + 'reference: last param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceB */', + 'expected' => true, + ], + 'reference: only param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceC */', + 'expected' => true, + ], + 'reference: last param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceD */', + 'expected' => true, + ], + 'reference: typed param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceE */', + 'expected' => true, + ], + 'reference: typed param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceF */', + 'expected' => true, + ], + 'reference: variadic param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceG */', + 'expected' => true, + ], + 'reference: foreach value' => [ + 'testMarker' => '/* testForeachValueByReference */', + 'expected' => true, + ], + 'reference: foreach key' => [ + 'testMarker' => '/* testForeachKeyByReference */', + 'expected' => true, + ], + 'reference: keyed short array, first value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceA */', + 'expected' => true, + ], + 'reference: keyed short array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceB */', + 'expected' => true, + ], + 'reference: unkeyed short array, only value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceC */', + 'expected' => true, + ], + 'reference: unkeyed short array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceD */', + 'expected' => true, + ], + 'reference: keyed long array, first value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceE */', + 'expected' => true, + ], + 'reference: keyed long array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceF */', + 'expected' => true, + ], + 'reference: unkeyed long array, only value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceG */', + 'expected' => true, + ], + 'reference: unkeyed long array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceH */', + 'expected' => true, + ], + 'reference: variable, assign by reference' => [ + 'testMarker' => '/* testAssignByReferenceA */', + 'expected' => true, + ], + 'reference: variable, assign by reference, spacing variation' => [ + 'testMarker' => '/* testAssignByReferenceB */', + 'expected' => true, + ], + 'reference: variable, assign by reference, concat assign' => [ + 'testMarker' => '/* testAssignByReferenceC */', + 'expected' => true, + ], + 'reference: property, assign by reference' => [ + 'testMarker' => '/* testAssignByReferenceD */', + 'expected' => true, + ], + 'reference: function return value, assign by reference' => [ + 'testMarker' => '/* testAssignByReferenceE */', + 'expected' => true, + ], + 'reference: function return value, assign by reference, null coalesce assign' => [ + 'testMarker' => '/* testAssignByReferenceF */', + 'expected' => true, + ], + 'reference: unkeyed short list, first var, assign by reference' => [ + 'testMarker' => '/* testShortListAssignByReferenceNoKeyA */', + 'expected' => true, + ], + 'reference: unkeyed short list, second var, assign by reference' => [ + 'testMarker' => '/* testShortListAssignByReferenceNoKeyB */', + 'expected' => true, + ], + 'reference: unkeyed short list, nested var, assign by reference' => [ + 'testMarker' => '/* testNestedShortListAssignByReferenceNoKey */', + 'expected' => true, + ], + 'reference: unkeyed long list, second var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceNoKeyA */', + 'expected' => true, + ], + 'reference: unkeyed long list, first nested var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceNoKeyB */', + 'expected' => true, + ], + 'reference: unkeyed long list, last nested var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceNoKeyC */', + 'expected' => true, + ], + 'reference: keyed short list, first nested var, assign by reference' => [ + 'testMarker' => '/* testNestedShortListAssignByReferenceWithKeyA */', + 'expected' => true, + ], + 'reference: keyed short list, last nested var, assign by reference' => [ + 'testMarker' => '/* testNestedShortListAssignByReferenceWithKeyB */', + 'expected' => true, + ], + 'reference: keyed long list, only var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceWithKeyA */', + 'expected' => true, + ], + 'reference: first param in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceA */', + 'expected' => true, + ], + 'reference: last param in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceB */', + 'expected' => true, + ], + 'reference: property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceC */', + 'expected' => true, + ], + 'reference: hierarchical self property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceD */', + 'expected' => true, + ], + 'reference: hierarchical parent property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceE */', + 'expected' => true, + ], + 'reference: hierarchical static property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceF */', + 'expected' => true, + ], + 'reference: static property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceG */', + 'expected' => true, + ], + 'reference: static property in function call, first with FQN, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceH */', + 'expected' => true, + ], + 'reference: static property in function call, last with FQN, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceI */', + 'expected' => true, + ], + 'reference: static property in function call, last with namespace relative name, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceJ */', + 'expected' => true, + ], + 'reference: static property in function call, last with PQN, pass by reference' => [ + 'testMarker' => '/* testPassByReferencePartiallyQualifiedName */', + 'expected' => true, + ], + 'reference: new by reference' => [ + 'testMarker' => '/* testNewByReferenceA */', + 'expected' => true, + ], + 'reference: new by reference as function call param' => [ + 'testMarker' => '/* testNewByReferenceB */', + 'expected' => true, + ], + 'reference: closure use by reference' => [ + 'testMarker' => '/* testUseByReference */', + 'expected' => true, + ], + 'reference: closure use by reference, first param, with comment' => [ + 'testMarker' => '/* testUseByReferenceWithCommentFirstParam */', + 'expected' => true, + ], + 'reference: closure use by reference, last param, with comment' => [ + 'testMarker' => '/* testUseByReferenceWithCommentSecondParam */', + 'expected' => true, + ], + 'reference: arrow fn declared to return by reference' => [ + 'testMarker' => '/* testArrowFunctionReturnByReference */', + 'expected' => true, + ], + 'bitwise and: first param default value in closure declaration' => [ + 'testMarker' => '/* testBitwiseAndExactParameterA */', + 'expected' => false, + ], + 'reference: param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceExactParameterB */', + 'expected' => true, + ], + 'reference: variadic param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceExactParameterC */', + 'expected' => true, + ], + 'bitwise and: last param default value in closure declaration' => [ + 'testMarker' => '/* testBitwiseAndExactParameterD */', + 'expected' => false, + ], + 'reference: typed param in arrow fn declaration, pass by reference' => [ + 'testMarker' => '/* testArrowFunctionPassByReferenceA */', + 'expected' => true, + ], + 'reference: variadic param in arrow fn declaration, pass by reference' => [ + 'testMarker' => '/* testArrowFunctionPassByReferenceB */', + 'expected' => true, + ], + 'reference: closure declared to return by reference' => [ + 'testMarker' => '/* testClosureReturnByReference */', + 'expected' => true, + ], + 'bitwise and: param default value in arrow fn declaration' => [ + 'testMarker' => '/* testBitwiseAndArrowFunctionInDefault */', + 'expected' => false, + ], + 'reference: param pass by ref in arrow function' => [ + 'testMarker' => '/* testParamPassByReference */', + 'expected' => true, + ], + 'issue-1284-short-list-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280A */', + 'expected' => true, + ], + 'issue-1284-short-list-directly-after-close-curly-control-structure-second-item' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280B */', + 'expected' => true, + ], + 'issue-1284-short-array-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280C */', + 'expected' => true, + ], + ]; + + }//end dataIsReference() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueAllGoodTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueAllGoodTest.xml new file mode 100644 index 00000000..f71fd566 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueAllGoodTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueConflictTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueConflictTest.xml new file mode 100644 index 00000000..732cfc51 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueConflictTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueNotEnoughLoopsTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueNotEnoughLoopsTest.xml new file mode 100644 index 00000000..9072dd71 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueNotEnoughLoopsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueTest.php new file mode 100644 index 00000000..76e56364 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueTest.php @@ -0,0 +1,89 @@ +process(); + $fixed = $phpcsFile->fixer->fixFile(); + + $this->assertTrue($fixed); + + }//end testReturnValueIsTrueWhenFileWasFixed() + + + /** + * Test that the return value of the fixFile() method is false when the file failed to make all fixes. + * + * @param string $standard The ruleset file to use for the test. + * + * @dataProvider dataReturnValueIsFalse + * + * @return void + */ + public function testReturnValueIsFalse($standard) + { + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $testCaseFile = __DIR__.'/Fixtures/test.inc'; + $phpcsFile = new LocalFile($testCaseFile, $ruleset, $config); + $phpcsFile->process(); + $fixed = $phpcsFile->fixer->fixFile(); + + $this->assertFalse($fixed); + + }//end testReturnValueIsFalse() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataReturnValueIsFalse() + { + return [ + 'when there is a fixer conflict' => [ + 'standard' => __DIR__.'/FixFileReturnValueConflictTest.xml', + ], + 'when the fixer ran out of loops before all fixes could be applied' => [ + 'standard' => __DIR__.'/FixFileReturnValueNotEnoughLoopsTest.xml', + ], + ]; + + }//end dataReturnValueIsFalse() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/AllGoodSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/AllGoodSniff.php new file mode 100644 index 00000000..20dbe2fe --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/AllGoodSniff.php @@ -0,0 +1,37 @@ +getTokens(); + + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE + || $tokens[($stackPtr + 1)]['length'] > 51 + ) { + return; + } + + $error = 'There should be 52 spaces after an ECHO keyword'; + $fix = $phpcsFile->addFixableError($error, ($stackPtr + 1), 'ShortSpace'); + if ($fix === true) { + $phpcsFile->fixer->replaceToken(($stackPtr + 1), str_repeat(' ', 52)); + } + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/ConflictSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/ConflictSniff.php new file mode 100644 index 00000000..ca7afb91 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/ConflictSniff.php @@ -0,0 +1,101 @@ +getTokens(); + + // Demand a blank line after the PHP open tag. + // This error is here to ensure something will be fixed in the file. + $nextNonWhitespace = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + + if (($tokens[$nextNonWhitespace]['line'] - $tokens[$stackPtr]['line']) !== 2) { + $error = 'There must be a single blank line after the PHP open tag'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'BlankLineAfterOpen'); + if ($fix === true) { + $phpcsFile->fixer->addNewline($stackPtr); + + // This return is here deliberately to force a new loop. + // This should ensure that loop 50 does *NOT* apply any fixes. + return; + } + } + + // Skip to the end of the file. + $stackPtr = ($phpcsFile->numTokens - 1); + + $eolCharLen = strlen($phpcsFile->eolChar); + $lastChars = substr($tokens[$stackPtr]['content'], ($eolCharLen * -1)); + + // Demand a newline at the end of a file. + if ($lastChars !== $phpcsFile->eolChar) { + $error = 'File must end with a newline character'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoNewlineEOF'); + if ($fix === true) { + $phpcsFile->fixer->addNewline($stackPtr); + } + } + + // Demand NO newline at the end of a file. + if ($lastChars === $phpcsFile->eolChar) { + $error = 'File must not end with a newline character'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NewlineEOF'); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + for ($i = $stackPtr; $i > 0; $i--) { + $newContent = rtrim($tokens[$i]['content'], $phpcsFile->eolChar); + $phpcsFile->fixer->replaceToken($i, $newContent); + + if ($newContent !== '') { + break; + } + } + + $phpcsFile->fixer->endChangeset(); + } + } + + // Ignore the rest of the file. + return $phpcsFile->numTokens; + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/NotEnoughLoopsSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/NotEnoughLoopsSniff.php new file mode 100644 index 00000000..e42d3fd7 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/NotEnoughLoopsSniff.php @@ -0,0 +1,40 @@ +getTokens(); + + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE + || $tokens[($stackPtr + 1)]['length'] > 60 + ) { + return; + } + + $error = 'There should be 60 spaces after an ECHO keyword'; + $fix = $phpcsFile->addFixableError($error, ($stackPtr + 1), 'ShortSpace'); + if ($fix === true) { + // The fixer deliberately only adds one space in each loop to ensure it runs out of loops before the file complies. + $phpcsFile->fixer->addContent($stackPtr, ' '); + } + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/ruleset.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/ruleset.xml new file mode 100644 index 00000000..6a202de3 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/ruleset.xml @@ -0,0 +1,4 @@ + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/test.inc new file mode 100644 index 00000000..76195b04 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/test.inc @@ -0,0 +1,2 @@ + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AnchorLinksTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AnchorLinksTest.xml new file mode 100644 index 00000000..17fb0cee --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AnchorLinksTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html new file mode 100644 index 00000000..a51ad92a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, blank lines §

+

This is a standard block.

+ + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
// First line of the code sample is
// deliberately empty.

// We also have a blank line in the middle.

// And a blank line at the end.
// First line of the code sample is
// deliberately empty.

// We also have a blank line in the middle.

// And a blank line at the end.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md new file mode 100644 index 00000000..ef25f893 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md @@ -0,0 +1,35 @@ +# GeneratorTest Coding Standard + +## Code Comparison, blank lines + +This is a standard block. + + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
+ + // First line of the code sample is + // deliberately empty. + + // We also have a blank line in the middle. + + // And a blank line at the end. + + + + // First line of the code sample is + // deliberately empty. + + // We also have a blank line in the middle. + + // And a blank line at the end. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt new file mode 100644 index 00000000..a7fd41d9 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt @@ -0,0 +1,18 @@ + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, BLANK LINES | +--------------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Checking handling of blank lines. | Invalid: Checking handling of blank lines. | +---------------------------------------------------------------------------------------------------- +| // First line of the code sample is | // First line of the code sample is | +| // deliberately empty. | // deliberately empty. | +| | | +| // We also have a blank line in the middle. | // We also have a blank line in the middle. | +| | | +| // And a blank line at the end. | // And a blank line at the end. | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html new file mode 100644 index 00000000..881bac30 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html @@ -0,0 +1,115 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, block length §

+

This is a standard block.

+ + + + + + + + + +
Valid: code sample A has more lines than B.Invalid: shorter.
// This code sample has more lines
// than the "invalid" one.
$one = 10;
$a = 10;
+ + + + + + + + + +
Valid: shorter.Invalid: code sample B has more lines than A.
echo $foo;// This code sample has more lines
// than the "valid" one.
print $foo;
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md new file mode 100644 index 00000000..526f110b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md @@ -0,0 +1,47 @@ +# GeneratorTest Coding Standard + +## Code Comparison, block length + +This is a standard block. + + + + + + + + + +
Valid: code sample A has more lines than B.Invalid: shorter.
+ + // This code sample has more lines + // than the "invalid" one. + $one = 10; + + + + $a = 10; + +
+ + + + + + + + + +
Valid: shorter.Invalid: code sample B has more lines than A.
+ + echo $foo; + + + + // This code sample has more lines + // than the "valid" one. + print $foo; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt new file mode 100644 index 00000000..c2fb737f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt @@ -0,0 +1,23 @@ + +---------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, BLOCK LENGTH | +---------------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: code sample A has more lines than B. | Invalid: shorter. | +---------------------------------------------------------------------------------------------------- +| // This code sample has more lines | $a = 10; | +| // than the "invalid" one. | | +| $one = 10; | | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: shorter. | Invalid: code sample B has more lines than A. | +---------------------------------------------------------------------------------------------------- +| echo $foo; | // This code sample has more lines | +| | // than the "valid" one. | +| | print $foo; | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html new file mode 100644 index 00000000..a325def1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, char encoding §

+

This is a standard block.

+ + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
<?php

// The above PHP tag is specifically testing
// handling of that in generated HTML doc.

// Now let's also check the handling of
// comparison operators in code samples...
$a = $b < $c;
$d = $e > $f;
$g = $h <= $i;
$j = $k >= $l;
$m = $n <=> $o;
<?php

// The above PHP tag is specifically testing
// handling of that in generated HTML doc.

// Now let's also check the handling of
// comparison operators in code samples
// in combination with "em" tags.
$a = $b < $c;
$d = $e > $f;
$g = $h <= $i;
$j = $k >= $l;
$m = $n <=> $o;
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md new file mode 100644 index 00000000..052d3cb3 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md @@ -0,0 +1,48 @@ +# GeneratorTest Coding Standard + +## Code Comparison, char encoding + +This is a standard block. + + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
+ + $f; + $g = $h <= $i; + $j = $k >= $l; + $m = $n <=> $o; + + + + $f; + $g = $h <= $i; + $j = $k >= $l; + $m = $n <=> $o; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt new file mode 100644 index 00000000..7ffcf4df --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt @@ -0,0 +1,26 @@ + +----------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, CHAR ENCODING | +----------------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Vestibulum et orci condimentum. | Invalid: Donec in nisl ut tortor convallis | +| | interdum. | +---------------------------------------------------------------------------------------------------- +| $f; | $a = $b < $c; | +| $g = $h <= $i; | $d = $e > $f; | +| $j = $k >= $l; | $g = $h <= $i; | +| $m = $n <=> $o; | $j = $k >= $l; | +| | $m = $n <=> $o; | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html new file mode 100644 index 00000000..b1e83a42 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html @@ -0,0 +1,106 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, line length §

+

Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0".
+Ref: squizlabs/PHP_CodeSniffer#2522

+ + + + + + + + + +
Valid: contains line which is too long.Invalid: contains line which is too long.
class Foo extends Bar implements Countable, Serializable
{
}
class Foo extends Bar
{
    public static function foobar($param1, $param2) {}
}
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md new file mode 100644 index 00000000..8dbf5642 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md @@ -0,0 +1,31 @@ +# GeneratorTest Coding Standard + +## Code Comparison, line length + +Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0". +Ref: squizlabs/PHP_CodeSniffer#2522 + + + + + + + + + +
Valid: contains line which is too long.Invalid: contains line which is too long.
+ + class Foo extends Bar implements Countable, Serializable + { + } + + + + class Foo extends Bar + { + public static function foobar($param1, $param2) {} + } + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt new file mode 100644 index 00000000..e8a665cd --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt @@ -0,0 +1,18 @@ + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, LINE LENGTH | +--------------------------------------------------------------- + +Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to +0". +Ref: squizlabs/PHP_CodeSniffer#2522 + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: contains line which is too long. | Invalid: contains line which is too long. | +---------------------------------------------------------------------------------------------------- +| class Foo extends Bar implements Countable, Serializable| class Foo extends Bar | +| { | { | +| } | public static function foobar($param1, $param2) {}| +| | } | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html new file mode 100644 index 00000000..dbe9966d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html @@ -0,0 +1,135 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Title, line wrapping §

+

This is a standard block.

+ + + + + + + + + +
Valid: exactly 45 character long description.Invalid: exactly 45 char long description---.
// Dummy.// Dummy.
+ + + + + + + + + +
Valid: exactly 46 character long description-.Invalid: exactly 46 character long description
// Dummy.// Dummy.
+ + + + + + + + + +
Valid: exactly 47 character long description--.Invalid: exactly 47 character long description.
// Dummy.// Dummy.
+ + + + + + + + + +
Valid: this description is longer than 46 characters and will wrap.Invalid: this description is longer than 46 characters and will wrap.
// Dummy.// Dummy.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md new file mode 100644 index 00000000..a0d6a8e6 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md @@ -0,0 +1,79 @@ +# GeneratorTest Coding Standard + +## Code Title, line wrapping + +This is a standard block. + + + + + + + + + +
Valid: exactly 45 character long description.Invalid: exactly 45 char long description---.
+ + // Dummy. + + + + // Dummy. + +
+ + + + + + + + + +
Valid: exactly 46 character long description-.Invalid: exactly 46 character long description
+ + // Dummy. + + + + // Dummy. + +
+ + + + + + + + + +
Valid: exactly 47 character long description--.Invalid: exactly 47 character long description.
+ + // Dummy. + + + + // Dummy. + +
+ + + + + + + + + +
Valid: this description is longer than 46 characters and will wrap.Invalid: this description is longer than 46 characters and will wrap.
+ + // Dummy. + + + + // Dummy. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt new file mode 100644 index 00000000..11925c4c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt @@ -0,0 +1,33 @@ + +------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE TITLE, LINE WRAPPING | +------------------------------------------------------------ + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: exactly 45 character long description. | Invalid: exactly 45 char long description---. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: exactly 46 character long description-. | Invalid: exactly 46 character long description | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: exactly 47 character long | Invalid: exactly 47 character long | +| description--. | description. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: this description is longer than 46 | Invalid: this description is longer than 46 | +| characters and will wrap. | characters and will wrap. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html new file mode 100644 index 00000000..65a5a25f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html @@ -0,0 +1,115 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Title, whitespace handling §

+

This is a standard block.

+ + + + + + + + + +
Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars.
// Dummy.// Dummy.
+ + + + + + + + + +
Valid: spaces at start + end of description.Invalid: spaces '     ' in description.
// Note: description above without the
// trailing whitespace fits in 46 chars.
// Dummy.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md new file mode 100644 index 00000000..e623ba98 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md @@ -0,0 +1,44 @@ +# GeneratorTest Coding Standard + +## Code Title, whitespace handling + +This is a standard block. + + + + + + + + + +
Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars.
+ + // Dummy. + + + + // Dummy. + +
+ + + + + + + + + +
Valid: spaces at start + end of description.Invalid: spaces '     ' in description.
+ + // Note: description above without the + // trailing whitespace fits in 46 chars. + + + + // Dummy. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt new file mode 100644 index 00000000..0db5a7df --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt @@ -0,0 +1,20 @@ + +------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE TITLE, WHITESPACE HANDLING | +------------------------------------------------------------------ + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: spaces at start of description. | Invalid: spaces at end making line > 46 chars. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: spaces at start + end of description. | Invalid: spaces ' ' in description. | +---------------------------------------------------------------------------------------------------- +| // Note: description above without the | // Dummy. | +| // trailing whitespace fits in 46 chars. | | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html new file mode 100644 index 00000000..e7226519 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

lowercase title §

+

This is a standard block.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md new file mode 100644 index 00000000..0d63b04a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## lowercase title + +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt new file mode 100644 index 00000000..c762a01d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------- +| GENERATORTEST CODING STANDARD: LOWERCASE TITLE | +-------------------------------------------------- + +This is a standard block. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html new file mode 100644 index 00000000..2640a6bf --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

This is a very very very very very very very very very very very long title §

+

This is a standard block.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md new file mode 100644 index 00000000..252f5fca --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## This is a very very very very very very very very very very very long title + +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt new file mode 100644 index 00000000..2787b8cd --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: THIS IS A VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY LONG TITLE | +-------------------------------------------------------------------------------------------------------------- + +This is a standard block. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.html new file mode 100644 index 00000000..b83b5e67 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.html @@ -0,0 +1,96 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Documentation Title PCRE Fallback §

+

Testing the document title can get determined from the sniff name if missing.

+

This file name contains an acronym on purpose to test the word splitting.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.md new file mode 100644 index 00000000..844f4fbb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.md @@ -0,0 +1,9 @@ +# GeneratorTest Coding Standard + +## Documentation Title PCRE Fallback + +Testing the document title can get determined from the sniff name if missing. + +This file name contains an acronym on purpose to test the word splitting. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.txt new file mode 100644 index 00000000..342cdfda --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.txt @@ -0,0 +1,9 @@ + +-------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: DOCUMENTATION TITLE PCRE FALLBACK | +-------------------------------------------------------------------- + +Testing the document title can get determined from the sniff name if missing. + +This file name contains an acronym on purpose to test the word splitting. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html new file mode 100644 index 00000000..1d992399 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html @@ -0,0 +1,107 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Table of Contents

+ +

URL enc@de non-àscíï chars §

+

The documentation title has non-ascii characters, which will be slugified for use in an HTML anchor link.

+

URL enc@de non-àscíï chars §

+

The documentation title has non-ascii characters, which will be slugified for use in an HTML anchor link.
+A duplicate anchor link will get a numeric suffix.

+

URL enc@de non-àscíï chars §

+

The documentation title has non-ascii characters, which will be slugified for use in an HTML anchor link.
+A duplicate anchor link will get a numeric suffix.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputEmpty.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputEmpty.txt new file mode 100644 index 00000000..e69de29b diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html new file mode 100644 index 00000000..59fcc7eb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, mismatched code blocks §

+

This doc has two code elements, one only has a title, one has actual code. Unbalanced

+ + + + + + + + + +
Code title
$a = 'Example code';
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.md new file mode 100644 index 00000000..bbd1f312 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Code Comparison, mismatched code blocks + +This doc has two code elements, one only has a title, one has actual code. Unbalanced + + + + + + + + + +
Code title
+ + + + + + $a = 'Example code'; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.txt new file mode 100644 index 00000000..85b3f31a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.txt @@ -0,0 +1,13 @@ + +-------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, MISMATCHED CODE BLOCKS | +-------------------------------------------------------------------------- + +This doc has two code elements, one only has a title, one has actual code. Unbalanced + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Code title | | +---------------------------------------------------------------------------------------------------- +| | $a = 'Example code'; | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html new file mode 100644 index 00000000..9f29d6af --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, missing code element §

+

This is a standard block.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.md new file mode 100644 index 00000000..4cd4b41b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## Code Comparison, missing code element + +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.txt new file mode 100644 index 00000000..0c3c6d13 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.txt @@ -0,0 +1,7 @@ + +------------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE COMPARISON, MISSING CODE ELEMENT | +------------------------------------------------------------------------ + +This is a standard block. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html new file mode 100644 index 00000000..35d9144a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html @@ -0,0 +1,101 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, no code §

+

This is a standard block.

+ + + + + +
Valid: no code.Invalid: no code.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.md new file mode 100644 index 00000000..afbf1063 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.md @@ -0,0 +1,13 @@ +# GeneratorTest Coding Standard + +## Code Comparison, no code + +This is a standard block. + + + + + +
Valid: no code.Invalid: no code.
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.txt new file mode 100644 index 00000000..f6091cab --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.txt @@ -0,0 +1,10 @@ + +----------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, NO CODE | +----------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: no code. | Invalid: no code. | +---------------------------------------------------------------------------------------------------- diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html new file mode 100644 index 00000000..b09f3ccf --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, no content §

+

This is a standard block.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.md new file mode 100644 index 00000000..1cea477f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## Code Comparison, no content + +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.txt new file mode 100644 index 00000000..0227cdc8 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, NO CONTENT | +-------------------------------------------------------------- + +This is a standard block. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html new file mode 100644 index 00000000..7ee4bee4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, one empty code element §

+

This doc has two code elements, but only one of them has a title and actual code.

+ + + + + + + + + +
Code title
$a = 'Example code';
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.md new file mode 100644 index 00000000..829f1363 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Code Comparison, one empty code element + +This doc has two code elements, but only one of them has a title and actual code. + + + + + + + + + +
Code title
+ + $a = 'Example code'; + + + + + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.txt new file mode 100644 index 00000000..7e937059 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.txt @@ -0,0 +1,13 @@ + +-------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, ONE EMPTY CODE ELEMENT | +-------------------------------------------------------------------------- + +This doc has two code elements, but only one of them has a title and actual code. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Code title | | +---------------------------------------------------------------------------------------------------- +| $a = 'Example code'; | | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html new file mode 100644 index 00000000..4cc553d4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, two empty code elements §

+

This doc has two code elements, but neither of them contain any information.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.md new file mode 100644 index 00000000..7d138767 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## Code Comparison, two empty code elements + +This doc has two code elements, but neither of them contain any information. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.txt new file mode 100644 index 00000000..775e7cee --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.txt @@ -0,0 +1,7 @@ + +--------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, TWO EMPTY CODE ELEMENTS | +--------------------------------------------------------------------------- + +This doc has two code elements, but neither of them contain any information. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html new file mode 100644 index 00000000..0efa0572 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html @@ -0,0 +1,101 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Title, empty §

+

This is a standard block.

+ + + + + +
// Dummy.// Dummy.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.md new file mode 100644 index 00000000..728ccc0b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.md @@ -0,0 +1,21 @@ +# GeneratorTest Coding Standard + +## Code Title, empty + +This is a standard block. + + + + + +
+ + // Dummy. + + + + // Dummy. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.txt new file mode 100644 index 00000000..d3ac256b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.txt @@ -0,0 +1,11 @@ + +---------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE TITLE, EMPTY | +---------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.html new file mode 100644 index 00000000..755f5a18 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.html @@ -0,0 +1,101 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Title, missing §

+

This is a standard block.

+ + + + + +
// Dummy.// Dummy.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.md new file mode 100644 index 00000000..98e58229 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.md @@ -0,0 +1,21 @@ +# GeneratorTest Coding Standard + +## Code Title, missing + +This is a standard block. + + + + + +
+ + // Dummy. + + + + // Dummy. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.txt new file mode 100644 index 00000000..3de51f08 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.txt @@ -0,0 +1,11 @@ + +------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE TITLE, MISSING | +------------------------------------------------------ + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html new file mode 100644 index 00000000..7d0d9aa5 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Documentation Title Empty §

+

The above "documentation" element has an empty title attribute.

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.md new file mode 100644 index 00000000..db8b2e40 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Documentation Title Empty + +The above "documentation" element has an empty title attribute. + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.txt new file mode 100644 index 00000000..85fe3779 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.txt @@ -0,0 +1,13 @@ + +------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: DOCUMENTATION TITLE EMPTY | +------------------------------------------------------------ + +The above "documentation" element has an empty title attribute. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html new file mode 100644 index 00000000..2f51fd47 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Documentation Title Missing §

+

The above "documentation" element is missing the title attribute.

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.md new file mode 100644 index 00000000..bd9ebfd1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Documentation Title Missing + +The above "documentation" element is missing the title attribute. + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.txt new file mode 100644 index 00000000..d4952038 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.txt @@ -0,0 +1,13 @@ + +-------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: DOCUMENTATION TITLE MISSING | +-------------------------------------------------------------- + +The above "documentation" element is missing the title attribute. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.html new file mode 100644 index 00000000..2eecc8ae --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.html @@ -0,0 +1,104 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, no content §

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.md new file mode 100644 index 00000000..8d5dbc25 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.md @@ -0,0 +1,24 @@ +# GeneratorTest Coding Standard + +## Standard Element, no content + + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.txt new file mode 100644 index 00000000..c0b96c7b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.txt @@ -0,0 +1,11 @@ + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, NO CONTENT | +--------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html new file mode 100644 index 00000000..798ae637 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

One Standard Block, No Code §

+

Documentation contains one standard block and no code comparison.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md new file mode 100644 index 00000000..f6130736 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## One Standard Block, No Code + +Documentation contains one standard block and no code comparison. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.txt new file mode 100644 index 00000000..75bbdcb0 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE STANDARD BLOCK, NO CODE | +-------------------------------------------------------------- + +Documentation contains one standard block and no code comparison. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html new file mode 100644 index 00000000..ceaab32a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html @@ -0,0 +1,97 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, blank line handling §

+

There is a blank line at the start of this standard.

+

And the above blank line is also deliberate to test part of the logic.

+

Let's also end on a blank line to test that too.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md new file mode 100644 index 00000000..f8663f14 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md @@ -0,0 +1,11 @@ +# GeneratorTest Coding Standard + +## Standard Element, blank line handling + +There is a blank line at the start of this standard. + +And the above blank line is also deliberate to test part of the logic. + +Let's also end on a blank line to test that too. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt new file mode 100644 index 00000000..1cdad0b1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt @@ -0,0 +1,11 @@ + +------------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, BLANK LINE HANDLING | +------------------------------------------------------------------------ + +There is a blank line at the start of this standard. + +And the above blank line is also deliberate to test part of the logic. + +Let's also end on a blank line to test that too. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html new file mode 100644 index 00000000..93a77d45 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html @@ -0,0 +1,96 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, handling of HTML tags §

+

The use of tags in standard descriptions is allowed and their handling should be safeguarded.
+Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md new file mode 100644 index 00000000..6183dc00 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md @@ -0,0 +1,8 @@ +# GeneratorTest Coding Standard + +## Standard Element, handling of HTML tags + +The use of *tags* in standard descriptions is allowed and their handling should be *safeguarded*. +Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt new file mode 100644 index 00000000..a464b86e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt @@ -0,0 +1,9 @@ + +-------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, HANDLING OF HTML TAGS | +-------------------------------------------------------------------------- + +The use of *tags* in standard descriptions is allowed and their handling should be *safeguarded*. +Other tags, like link, bold, are not allowed +and will be encoded for display when the HTML or Markdown report is used. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html new file mode 100644 index 00000000..8cf7c341 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html @@ -0,0 +1,98 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, indentation should be ignored §

+

This line has no indentation.
+This line has 4 spaces indentation.
+This line has 8 spaces indentation.
+This line has 4 spaces indentation.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md new file mode 100644 index 00000000..46bea4c3 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md @@ -0,0 +1,10 @@ +# GeneratorTest Coding Standard + +## Standard Element, indentation should be ignored + +This line has no indentation. +This line has 4 spaces indentation. +This line has 8 spaces indentation. +This line has 4 spaces indentation. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt new file mode 100644 index 00000000..fef00b9d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt @@ -0,0 +1,10 @@ + +---------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, INDENTATION SHOULD BE IGNORED | +---------------------------------------------------------------------------------- + +This line has no indentation. +This line has 4 spaces indentation. +This line has 8 spaces indentation. +This line has 4 spaces indentation. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html new file mode 100644 index 00000000..b9f4038a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html @@ -0,0 +1,97 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, line wrapping handling §

+

This line has to be exactly 99 chars to test part of the logic.------------------------------------
+And this line has to be exactly 100 chars.----------------------------------------------------------
+And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md new file mode 100644 index 00000000..c94bed46 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md @@ -0,0 +1,9 @@ +# GeneratorTest Coding Standard + +## Standard Element, line wrapping handling + +This line has to be exactly 99 chars to test part of the logic.------------------------------------ +And this line has to be exactly 100 chars.---------------------------------------------------------- +And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt new file mode 100644 index 00000000..6f09fbe3 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt @@ -0,0 +1,11 @@ + +--------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, LINE WRAPPING HANDLING | +--------------------------------------------------------------------------- + +This line has to be exactly 99 chars to test part of the logic.------------------------------------ +And this line has to be exactly 100 chars.---------------------------------------------------------- +And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum +dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi +ultrices in odio pharetra commodo. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html new file mode 100644 index 00000000..9aa1d620 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html @@ -0,0 +1,200 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Table of Contents

+ +

Code Comparison Only, Missing Standard Block §

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+

One Standard Block, Code Comparison §

+

Documentation contains one standard block and one code comparison.

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+

One Standard Block, No Code §

+

Documentation contains one standard block and no code comparison.

+

One Standard Block, Two Code Comparisons §

+

Documentation contains one standard block and two code comparisons.

+ + + + + + + + + +
Valid: Etiam commodo magna at vestibulum blandit.Invalid: Vivamus lacinia ante velit.
class Code {}class Comparison {}
+ + + + + + + + + +
Valid: Pellentesque nisi neque.Invalid: Mauris dictum metus quis maximus pharetra.
$one = 10;$a = 10;
+

Two Standard Blocks, No Code §

+

This is standard block one.

+

This is standard block two.

+

Two Standard Blocks, One Code Comparison §

+

This is standard block one.

+ + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
class Code {}class Comparison {}
+

This is standard block two.

+

Two Standard Blocks, Three Code Comparisons §

+

This is standard block one.

+ + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
class Code {}class Comparison {}
+

This is standard block two.

+ + + + + + + + + +
Valid: Pellentesque nisi neque.Invalid: Mauris dictum metus quis maximus pharetra.
$one = 10;$a = 10;
+ + + + + + + + + +
Valid: Quisque sagittis nisi vitae.Invalid: Morbi ac libero vitae lorem.
echo $foo;print $foo;
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md new file mode 100644 index 00000000..fcbfcefe --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md @@ -0,0 +1,177 @@ +# GeneratorTest Coding Standard + +## Code Comparison Only, Missing Standard Block + + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +## One Standard Block, Code Comparison + +Documentation contains one standard block and one code comparison. + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +## One Standard Block, No Code + +Documentation contains one standard block and no code comparison. + +## One Standard Block, Two Code Comparisons + +Documentation contains one standard block and two code comparisons. + + + + + + + + + +
Valid: Etiam commodo magna at vestibulum blandit.Invalid: Vivamus lacinia ante velit.
+ + class Code {} + + + + class Comparison {} + +
+ + + + + + + + + +
Valid: Pellentesque nisi neque.Invalid: Mauris dictum metus quis maximus pharetra.
+ + $one = 10; + + + + $a = 10; + +
+ +## Two Standard Blocks, No Code + +This is standard block one. +This is standard block two. + +## Two Standard Blocks, One Code Comparison + +This is standard block one. + + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
+ + class Code {} + + + + class Comparison {} + +
+This is standard block two. + +## Two Standard Blocks, Three Code Comparisons + +This is standard block one. + + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
+ + class Code {} + + + + class Comparison {} + +
+This is standard block two. + + + + + + + + + +
Valid: Pellentesque nisi neque.Invalid: Mauris dictum metus quis maximus pharetra.
+ + $one = 10; + + + + $a = 10; + +
+ + + + + + + + + +
Valid: Quisque sagittis nisi vitae.Invalid: Morbi ac libero vitae lorem.
+ + echo $foo; + + + + print $foo; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt new file mode 100644 index 00000000..4ca1dbca --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt @@ -0,0 +1,106 @@ + +------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON ONLY, MISSING STANDARD BLOCK | +------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + + +---------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE STANDARD BLOCK, CODE COMPARISON | +---------------------------------------------------------------------- + +Documentation contains one standard block and one code comparison. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + + +-------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE STANDARD BLOCK, NO CODE | +-------------------------------------------------------------- + +Documentation contains one standard block and no code comparison. + + +--------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE STANDARD BLOCK, TWO CODE COMPARISONS | +--------------------------------------------------------------------------- + +Documentation contains one standard block and two code comparisons. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Etiam commodo magna at vestibulum | Invalid: Vivamus lacinia ante velit. | +| blandit. | | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Pellentesque nisi neque. | Invalid: Mauris dictum metus quis maximus | +| | pharetra. | +---------------------------------------------------------------------------------------------------- +| $one = 10; | $a = 10; | +---------------------------------------------------------------------------------------------------- + + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: TWO STANDARD BLOCKS, NO CODE | +--------------------------------------------------------------- + +This is standard block one. + +This is standard block two. + + +--------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: TWO STANDARD BLOCKS, ONE CODE COMPARISON | +--------------------------------------------------------------------------- + +This is standard block one. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Vestibulum et orci condimentum. | Invalid: Donec in nisl ut tortor convallis | +| | interdum. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + +This is standard block two. + + +------------------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: TWO STANDARD BLOCKS, THREE CODE COMPARISONS | +------------------------------------------------------------------------------ + +This is standard block one. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Vestibulum et orci condimentum. | Invalid: Donec in nisl ut tortor convallis | +| | interdum. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + +This is standard block two. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Pellentesque nisi neque. | Invalid: Mauris dictum metus quis maximus | +| | pharetra. | +---------------------------------------------------------------------------------------------------- +| $one = 10; | $a = 10; | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Quisque sagittis nisi vitae. | Invalid: Morbi ac libero vitae lorem. | +---------------------------------------------------------------------------------------------------- +| echo $foo; | print $foo; | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html new file mode 100644 index 00000000..82fe7500 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

One element correct, one element wrong level §

+

This is a standard block at the correct level.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md new file mode 100644 index 00000000..aa9cc472 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## One element correct, one element wrong level + +This is a standard block at the correct level. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt new file mode 100644 index 00000000..4d1aaeaa --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt @@ -0,0 +1,7 @@ + +------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE ELEMENT CORRECT, ONE ELEMENT WRONG LEVEL | +------------------------------------------------------------------------------- + +This is a standard block at the correct level. + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html new file mode 100644 index 00000000..de06568d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Superfluous code element §

+

This is a standard block.

+ + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
$valid = true;$invalid = true;
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md new file mode 100644 index 00000000..f6cdad94 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Superfluous code element + +This is a standard block. + + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
+ + $valid = true; + + + + $invalid = true; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt new file mode 100644 index 00000000..1307eebf --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt @@ -0,0 +1,13 @@ + +----------------------------------------------------------- +| GENERATORTEST CODING STANDARD: SUPERFLUOUS CODE ELEMENT | +----------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Checking handling of blank lines. | Invalid: Checking handling of blank lines. | +---------------------------------------------------------------------------------------------------- +| $valid = true; | $invalid = true; | +---------------------------------------------------------------------------------------------------- + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/HTMLDouble.php b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/HTMLDouble.php new file mode 100644 index 00000000..695c0c6d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/HTMLDouble.php @@ -0,0 +1,70 @@ +Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION# + +'; + + // Use the correct line endings based on the OS. + return str_replace("\n", PHP_EOL, $output).PHP_EOL; + } + + /** + * Retrieve the _real_ footer of the HTML page. + * + * @return string + */ + public function getRealFooter() + { + return parent::getFormattedFooter(); + } + + /** + * [VISIBILITY WIDENING ONLY] Print the header of the HTML page. + * + * @return void + */ + public function printHeader() + { + parent::printHeader(); + } + + /** + * [VISIBILITY WIDENING ONLY] Print the table of contents for the standard. + * + * @return void + */ + public function printToc() + { + parent::printToc(); + } + + /** + * [VISIBILITY WIDENING ONLY] Print the footer of the HTML page. + * + * @return void + */ + public function printFooter() + { + parent::printFooter(); + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/MarkdownDouble.php b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/MarkdownDouble.php new file mode 100644 index 00000000..79dc6b0b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/MarkdownDouble.php @@ -0,0 +1,68 @@ +getTitle($doc), PHP_EOL; + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml new file mode 100644 index 00000000..bcaf82bb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml new file mode 100644 index 00000000..c479a7fd --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml @@ -0,0 +1,35 @@ + + + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + + + echo $foo; + ]]> + + + print $foo; + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml new file mode 100644 index 00000000..c366553f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml @@ -0,0 +1,42 @@ + + + + + + + $f; +$g = $h <= $i; +$j = $k >= $l; +$m = $n <=> $o; + ]]> + + + + +// The above PHP tag is specifically testing +// handling of that in generated HTML doc. + +// Now let's also check the handling of +// comparison operators in code samples +// in combination with "em" tags. +$a = $b < $c; +$d = $e > $f; +$g = $h <= $i; +$j = $k >= $l; +$m = $n <=> $o; + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml new file mode 100644 index 00000000..b4431ea8 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml @@ -0,0 +1,25 @@ + + + + + + + Countable, Serializable +{ +} + ]]> + + + foobar($param1, $param2) {} +} + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml new file mode 100644 index 00000000..b773f7a8 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml new file mode 100644 index 00000000..28297202 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml new file mode 100644 index 00000000..a4078e3d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml new file mode 100644 index 00000000..24489276 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitlePCREFallbackStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitlePCREFallbackStandard.xml new file mode 100644 index 00000000..1aa3849b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitlePCREFallbackStandard.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug1Standard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug1Standard.xml new file mode 100644 index 00000000..4edae691 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug1Standard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug2Standard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug2Standard.xml new file mode 100644 index 00000000..43956e3f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug2Standard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug3Standard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug3Standard.xml new file mode 100644 index 00000000..43956e3f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug3Standard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml new file mode 100644 index 00000000..10c47bf4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml new file mode 100644 index 00000000..3e34c3f9 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml @@ -0,0 +1,8 @@ + + + tags in standard descriptions is allowed and their handling should be safeguarded. + Other tags, like link, bold, are not allowed and will be encoded for display when the HTML or Markdown report is used. + ]]> + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml new file mode 100644 index 00000000..b2ec6c5e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml new file mode 100644 index 00000000..66bbb962 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMismatchedCodeElmsStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMismatchedCodeElmsStandard.xml new file mode 100644 index 00000000..d0cfff41 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMismatchedCodeElmsStandard.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMissingCodeElmStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMissingCodeElmStandard.xml new file mode 100644 index 00000000..999901eb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMissingCodeElmStandard.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoCodeStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoCodeStandard.xml new file mode 100644 index 00000000..54b50ff8 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoCodeStandard.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoContentStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoContentStandard.xml new file mode 100644 index 00000000..0dfb12fa --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoContentStandard.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonOneEmptyCodeElmStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonOneEmptyCodeElmStandard.xml new file mode 100644 index 00000000..b4067441 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonOneEmptyCodeElmStandard.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonTwoEmptyCodeElmsStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonTwoEmptyCodeElmsStandard.xml new file mode 100644 index 00000000..e6cb0714 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonTwoEmptyCodeElmsStandard.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleEmptyStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleEmptyStandard.xml new file mode 100644 index 00000000..034bdf2f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleEmptyStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleMissingStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleMissingStandard.xml new file mode 100644 index 00000000..89599dd2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleMissingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleEmptyStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleEmptyStandard.xml new file mode 100644 index 00000000..c3ab071d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleEmptyStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleMissingStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleMissingStandard.xml new file mode 100644 index 00000000..974071d9 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleMissingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/StandardNoContentStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/StandardNoContentStandard.xml new file mode 100644 index 00000000..e6934706 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/StandardNoContentStandard.xml @@ -0,0 +1,15 @@ + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml new file mode 100644 index 00000000..83afee8e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml @@ -0,0 +1,2 @@ + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml new file mode 100644 index 00000000..ca8290f1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml @@ -0,0 +1,2 @@ + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml new file mode 100644 index 00000000..c2af9098 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml @@ -0,0 +1,14 @@ + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml new file mode 100644 index 00000000..c3ce35cd --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml new file mode 100644 index 00000000..fc014949 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml new file mode 100644 index 00000000..19559e67 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml @@ -0,0 +1,31 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml new file mode 100644 index 00000000..f5f621ec --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml new file mode 100644 index 00000000..a5b3a321 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml @@ -0,0 +1,24 @@ + + + + + + + Code {} + ]]> + + + Comparison {} + ]]> + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml new file mode 100644 index 00000000..540ac7ea --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml @@ -0,0 +1,48 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + + + echo $foo; + ]]> + + + print $foo; + ]]> + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml new file mode 100644 index 00000000..68519dd2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml new file mode 100644 index 00000000..6c1dd164 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml new file mode 100644 index 00000000..333786a3 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml new file mode 100644 index 00000000..c9ec3227 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php new file mode 100644 index 00000000..1e56bf9c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php @@ -0,0 +1,12 @@ + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/GeneratorTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/GeneratorTest.php new file mode 100644 index 00000000..8fb0ee25 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/GeneratorTest.php @@ -0,0 +1,227 @@ + $expected The expected list of found docs. + * + * @dataProvider dataConstructor + * + * @return void + */ + public function testConstructor($standard, array $expected) + { + // Set up the ruleset. + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MockGenerator($ruleset); + $this->assertSame($expected, $generator->docFiles); + + }//end testConstructor() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataConstructor() + { + $pathToDocsInFixture = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'; + $pathToDocsInFixture .= DIRECTORY_SEPARATOR.'StandardWithDocs'; + $pathToDocsInFixture .= DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR; + + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'expected' => [], + ], + 'Standard with an invalid doc file' => [ + 'standard' => __DIR__.'/NoValidDocsTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'NoDocumentationElementStandard.xml', + ], + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockNoCodeStandard.xml', + ], + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'NoContentStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneCodeComparisonNoStandardStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockCodeComparisonStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockNoCodeStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockTwoCodeComparisonsStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksNoCodeStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksOneCodeComparisonStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksThreeCodeComparisonsStandard.xml', + ], + ], + ]; + + }//end dataConstructor() + + + /** + * Verify that an XML doc which isn't valid documentation yields an Exception to warn devs. + * + * This should not be hidden via defensive coding! + * + * @return void + */ + public function testGeneratingInvalidDocsResultsInException() + { + // Set up the ruleset. + $standard = __DIR__.'/NoValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + if (PHP_VERSION_ID >= 80000) { + $exception = 'TypeError'; + $message = 'processSniff(): Argument #1 ($doc) must be of type DOMNode, null given'; + } else if (PHP_VERSION_ID >= 70000) { + $exception = 'TypeError'; + $message = 'processSniff() must be an instance of DOMNode, null given'; + } else { + $exception = 'PHPUnit_Framework_Error'; + $message = 'processSniff() must be an instance of DOMNode, null given'; + } + + if (method_exists($this, 'expectExceptionMessage') === true) { + // PHPUnit 5.2.0+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // Ancient PHPUnit. + $this->setExpectedException($exception, $message); + } + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGeneratingInvalidDocsResultsInException() + + + /** + * Verify the wiring for the generate() function. + * + * @param string $standard The standard to use for the test. + * @param string $expected The expected function output. + * + * @dataProvider dataGeneratingDocs + * + * @return void + */ + public function testGeneratingDocs($standard, $expected) + { + // Set up the ruleset. + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $this->expectOutputString($expected); + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGeneratingDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataGeneratingDocs() + { + $multidocExpected = []; + $multidocExpected[] = 'No Content'; + $multidocExpected[] = 'Code Comparison Only, Missing Standard Block'; + $multidocExpected[] = 'One Standard Block, Code Comparison'; + $multidocExpected[] = 'One Standard Block, No Code'; + $multidocExpected[] = 'One Standard Block, Two Code Comparisons'; + $multidocExpected[] = 'Two Standard Blocks, No Code'; + $multidocExpected[] = 'Two Standard Blocks, One Code Comparison'; + $multidocExpected[] = 'Two Standard Blocks, Three Code Comparisons'; + $multidocExpected = implode(PHP_EOL, $multidocExpected).PHP_EOL; + + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'expected' => '', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'expected' => 'One Standard Block, No Code'.PHP_EOL, + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'expected' => $multidocExpected, + ], + ]; + + }//end dataGeneratingDocs() + + + /** + * Verify that if the `` title is missing, it will fallback to the file name + * and split the CamelCaps name correctly. + * + * @return void + */ + public function testGetTitleFallbackToFilename() + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $sniffs = 'StandardWithDocs.Content.DocumentationTitlePCREFallback'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + // Make the test OS independent. + $this->expectOutputString('Documentation Title PCRE Fallback'.PHP_EOL); + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGetTitleFallbackToFilename() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/HTMLTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/HTMLTest.php new file mode 100644 index 00000000..91cd7d1e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/HTMLTest.php @@ -0,0 +1,426 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.html', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.html', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.html', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.html', + ], + 'Documentation title: fallback to file name' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.html', + ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.html', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.html', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.html', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.html', + ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.html', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.html', + ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.html', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.html', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.html', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.html', + ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Invalid: code comparison mismatched code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html', + ], + 'Invalid: code comparison only has one code elm' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html', + ], + 'Invalid: code elements have no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html', + ], + 'Invalid: code comparison element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html', + ], + 'Invalid: code comparison two code elms, one empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html', + ], + 'Invalid: code comparison two empty code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html', + ], + 'Invalid: code title attributes are empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html', + ], + 'Invalid: code title attributes missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.html', + ], + 'Invalid: documentation title attribute is empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html', + ], + 'Invalid: documentation title attribute missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html', + ], + 'Invalid: standard element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.html', + ], + ]; + + }//end dataDocSpecifics() + + + /** + * Test anchor links in the generated docs are slugified and unique. + * + * @return void + */ + public function testAnchorLinks() + { + // Set up the ruleset. + $standard = __DIR__.'/AnchorLinksTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $pathToExpected = __DIR__.'/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html'; + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testAnchorLinks() + + + /** + * Test the generated footer. + * + * @return void + */ + public function testFooter() + { + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $regex = '`^
'; + $regex .= 'Documentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; + $regex .= ' by PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+'; + $regex .= '
\R \R\R$`'; + + $generator = new HTMLDouble($ruleset); + $footer = $generator->getRealFooter(); + + if (method_exists($this, 'assertMatchesRegularExpression') === true) { + $this->assertMatchesRegularExpression($regex, $footer); + } else { + // PHPUnit < 9.1.0. + $this->assertRegExp($regex, $footer); + } + + }//end testFooter() + + + /** + * Safeguard that the footer logic doesn't permanently change the error level. + * + * @runInSeparateProcess + * @preserveGlobalState disabled + * + * @return void + */ + public function testFooterResetsErrorReportingToOriginalSetting() + { + $expected = error_reporting(); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new HTMLDouble($ruleset); + $generator->getRealFooter(); + + $this->assertSame($expected, error_reporting()); + + }//end testFooterResetsErrorReportingToOriginalSetting() + + + /** + * Safeguard that users won't see a PHP warning about the timezone not being set when calling date(). + * + * The warning we don't want to see is: + * "date(): It is not safe to rely on the system's timezone settings. You are *required* to use + * the date.timezone setting or the date_default_timezone_set() function. In case you used any of + * those methods and you are still getting this warning, you most likely misspelled the timezone + * identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select + * your timezone." + * + * JRF: Based on my tests, the warning only occurs on PHP < 7.0, but never a bad thing to safeguard this + * on a wider range of PHP versions. + * + * Note: as of PHP 8.2, PHP no longer accepts an empty string as timezone and will use `UTC` instead, + * so the warning on calling date() in the code itself would not display anyway. + * + * @requires PHP < 8.2 + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testFooterDoesntThrowWarningOnMissingTimezone() + { + $originalIni = @ini_set('date.timezone', ''); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new HTMLDouble($ruleset); + $generator->getRealFooter(); + + // Reset the timezone to its original state. + ini_set('date.timezone', $originalIni); + + }//end testFooterDoesntThrowWarningOnMissingTimezone() + + + /** + * Perfunctory test to verify that extenders which call deprecated methods will see a deprecation notice. + * + * Note: not all deprecated methods are tested as some need arguments. + * + * @param string $methodName Name of the deprecated method to test. + * + * @dataProvider dataCallingDeprecatedMethodThrowsDeprecationNotice + * + * @return void + */ + public function testCallingDeprecatedMethodThrowsDeprecationNotice($methodName) + { + $exceptionClass = 'PHPUnit\Framework\Error\Deprecated'; + if (class_exists($exceptionClass) === false) { + $exceptionClass = 'PHPUnit_Framework_Error_Deprecated'; + } + + $regex = '`^The PHP_CodeSniffer\\\\Generators\\\\HTML::%s\(\) method is deprecated\. Use "echo [^\s]+::%s\(\)" instead\.$`'; + $regex = sprintf($regex, preg_quote($methodName, '`'), str_replace('print', 'getFormatted', $methodName)); + + if (method_exists($this, 'expectExceptionMessageMatches') === true) { + $this->expectException($exceptionClass); + $this->expectExceptionMessageMatches($regex); + } else if (method_exists($this, 'expectExceptionMessageRegExp') === true) { + // PHPUnit < 8.4.0. + $this->expectException($exceptionClass); + $this->expectExceptionMessageRegExp($regex); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedExceptionRegExp($exceptionClass, $regex); + } + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new HTMLDouble($ruleset); + $generator->$methodName(); + + }//end testCallingDeprecatedMethodThrowsDeprecationNotice() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataCallingDeprecatedMethodThrowsDeprecationNotice() + { + return [ + 'printHeader()' => ['printHeader'], + 'printToc()' => ['printToc'], + 'printFooter()' => ['printFooter'], + ]; + + }//end dataCallingDeprecatedMethodThrowsDeprecationNotice() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/MarkdownTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/MarkdownTest.php new file mode 100644 index 00000000..f9fd4779 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/MarkdownTest.php @@ -0,0 +1,397 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new MarkdownDouble($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.md', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.md', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new MarkdownDouble($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.md', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.md', + ], + 'Documentation title: fallback to file name' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.md', + ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.md', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.md', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.md', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.md', + ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.md', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.md', + ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.md', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.md', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.md', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.md', + ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Invalid: code comparison mismatched code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.md', + ], + 'Invalid: code comparison only has one code elm' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.md', + ], + 'Invalid: code elements have no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.md', + ], + 'Invalid: code comparison element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.md', + ], + 'Invalid: code comparison two code elms, one empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.md', + ], + 'Invalid: code comparison two empty code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.md', + ], + 'Invalid: code title attributes are empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.md', + ], + 'Invalid: code title attributes missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.md', + ], + 'Invalid: documentation title attribute is empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.md', + ], + 'Invalid: documentation title attribute missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.md', + ], + 'Invalid: standard element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.md', + ], + ]; + + }//end dataDocSpecifics() + + + /** + * Test the generated footer. + * + * @return void + */ + public function testFooter() + { + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $regex = '`^\RDocumentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; + $regex .= ' by \[PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+\]\(https://github\.com/PHPCSStandards/PHP_CodeSniffer\)\R$`'; + + $generator = new MarkdownDouble($ruleset); + $footer = $generator->getRealFooter(); + + if (method_exists($this, 'assertMatchesRegularExpression') === true) { + $this->assertMatchesRegularExpression($regex, $footer); + } else { + // PHPUnit < 9.1.0. + $this->assertRegExp($regex, $footer); + } + + }//end testFooter() + + + /** + * Safeguard that the footer logic doesn't permanently change the error level. + * + * @runInSeparateProcess + * @preserveGlobalState disabled + * + * @return void + */ + public function testFooterResetsErrorReportingToOriginalSetting() + { + $expected = error_reporting(); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MarkdownDouble($ruleset); + $generator->getRealFooter(); + + $this->assertSame($expected, error_reporting()); + + }//end testFooterResetsErrorReportingToOriginalSetting() + + + /** + * Safeguard that users won't see a PHP warning about the timezone not being set when calling date(). + * + * The warning we don't want to see is: + * "date(): It is not safe to rely on the system's timezone settings. You are *required* to use + * the date.timezone setting or the date_default_timezone_set() function. In case you used any of + * those methods and you are still getting this warning, you most likely misspelled the timezone + * identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select + * your timezone." + * + * JRF: Based on my tests, the warning only occurs on PHP < 7.0, but never a bad thing to safeguard this + * on a wider range of PHP versions. + * + * Note: as of PHP 8.2, PHP no longer accepts an empty string as timezone and will use `UTC` instead, + * so the warning on calling date() in the code itself would not display anyway. + * + * @requires PHP < 8.2 + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testFooterDoesntThrowWarningOnMissingTimezone() + { + $originalIni = @ini_set('date.timezone', ''); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MarkdownDouble($ruleset); + $generator->getRealFooter(); + + // Reset the timezone to its original state. + ini_set('date.timezone', $originalIni); + + }//end testFooterDoesntThrowWarningOnMissingTimezone() + + + /** + * Perfunctory test to verify that extenders which call deprecated methods will see a deprecation notice. + * + * Note: not all deprecated methods are tested as some need arguments. + * + * @param string $methodName Name of the deprecated method to test. + * + * @dataProvider dataCallingDeprecatedMethodThrowsDeprecationNotice + * + * @return void + */ + public function testCallingDeprecatedMethodThrowsDeprecationNotice($methodName) + { + $exceptionClass = 'PHPUnit\Framework\Error\Deprecated'; + if (class_exists($exceptionClass) === false) { + $exceptionClass = 'PHPUnit_Framework_Error_Deprecated'; + } + + $regex = '`^The PHP_CodeSniffer\\\\Generators\\\\Markdown::%s\(\) method is deprecated\. Use "echo [^\s]+::%s\(\)" instead\.$`'; + $regex = sprintf($regex, preg_quote($methodName, '`'), str_replace('print', 'getFormatted', $methodName)); + + if (method_exists($this, 'expectExceptionMessageMatches') === true) { + $this->expectException($exceptionClass); + $this->expectExceptionMessageMatches($regex); + } else if (method_exists($this, 'expectExceptionMessageRegExp') === true) { + // PHPUnit < 8.4.0. + $this->expectException($exceptionClass); + $this->expectExceptionMessageRegExp($regex); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedExceptionRegExp($exceptionClass, $regex); + } + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MarkdownDouble($ruleset); + $generator->$methodName(); + + }//end testCallingDeprecatedMethodThrowsDeprecationNotice() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataCallingDeprecatedMethodThrowsDeprecationNotice() + { + return [ + 'printHeader()' => ['printHeader'], + 'printFooter()' => ['printFooter'], + ]; + + }//end dataCallingDeprecatedMethodThrowsDeprecationNotice() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoDocsTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoDocsTest.xml new file mode 100644 index 00000000..efb29990 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoDocsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoValidDocsTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoValidDocsTest.xml new file mode 100644 index 00000000..9f5c9c49 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoValidDocsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/OneDocTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/OneDocTest.xml new file mode 100644 index 00000000..50e64a88 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/OneDocTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/StructureDocsTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/StructureDocsTest.xml new file mode 100644 index 00000000..6199e287 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/StructureDocsTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Generators/TextTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/TextTest.php new file mode 100644 index 00000000..90bb7bf8 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Generators/TextTest.php @@ -0,0 +1,245 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new Text($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.txt', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.txt', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new Text($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.txt', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.txt', + ], + 'Documentation title: fallback to file name' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.txt', + ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.txt', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.txt', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.txt', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.txt', + ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.txt', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.txt', + ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.txt', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.txt', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.txt', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.txt', + ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Invalid: code comparison mismatched code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.txt', + ], + 'Invalid: code comparison only has one code elm' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.txt', + ], + 'Invalid: code elements have no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.txt', + ], + 'Invalid: code comparison element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.txt', + ], + 'Invalid: code comparison two code elms, one empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.txt', + ], + 'Invalid: code comparison two empty code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.txt', + ], + 'Invalid: code title attributes are empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.txt', + ], + 'Invalid: code title attributes missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.txt', + ], + 'Invalid: documentation title attribute is empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.txt', + ], + 'Invalid: documentation title attribute missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.txt', + ], + 'Invalid: standard element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.txt', + ], + ]; + + }//end dataDocSpecifics() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/AbstractRulesetTestCase.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/AbstractRulesetTestCase.php new file mode 100644 index 00000000..41c63944 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/AbstractRulesetTestCase.php @@ -0,0 +1,115 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHPUnit\Framework\TestCase; + +abstract class AbstractRulesetTestCase extends TestCase +{ + + /** + * The fully qualified name of the PHPCS runtime exception class. + * + * @var string + */ + const RUNTIME_EXCEPTION = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + + + /** + * Asserts that an object has a specified property in a PHPUnit cross-version compatible manner. + * + * @param string $propertyName The name of the property. + * @param object $object The object on which to check whether the property exists. + * @param string $message Optional failure message to display. + * + * @return void + */ + protected function assertXObjectHasProperty($propertyName, $object, $message='') + { + if (method_exists($this, 'assertObjectHasProperty') === true) { + $this->assertObjectHasProperty($propertyName, $object, $message); + } else { + // PHPUnit < 9.6.11. + $this->assertObjectHasAttribute($propertyName, $object, $message); + } + + }//end assertXObjectHasProperty() + + + /** + * Asserts that an object does not have a specified property + * in a PHPUnit cross-version compatible manner. + * + * @param string $propertyName The name of the property. + * @param object $object The object on which to check whether the property exists. + * @param string $message Optional failure message to display. + * + * @return void + */ + protected function assertXObjectNotHasProperty($propertyName, $object, $message='') + { + if (method_exists($this, 'assertObjectNotHasProperty') === true) { + $this->assertObjectNotHasProperty($propertyName, $object, $message); + } else { + // PHPUnit < 9.6.11. + $this->assertObjectNotHasAttribute($propertyName, $object, $message); + } + + }//end assertXObjectNotHasProperty() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException with a certain message + * in a PHPUnit cross-version compatible manner. + * + * @param string $message The expected exception message. + * + * @return void + */ + protected function expectRuntimeExceptionMessage($message) + { + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException(self::RUNTIME_EXCEPTION, $message); + } + + }//end expectRuntimeExceptionMessage() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException which matches a regex patten + * in a PHPUnit cross-version compatible manner. + * + * @param string $regex The regex which should match. + * + * @return void + */ + protected function expectRuntimeExceptionRegex($regex) + { + if (method_exists($this, 'expectExceptionMessageMatches') === true) { + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessageMatches($regex); + } else if (method_exists($this, 'expectExceptionMessageRegExp') === true) { + // PHPUnit < 8.4.0. + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessageRegExp($regex); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedExceptionRegExp(self::RUNTIME_EXCEPTION, $regex); + } + + }//end expectRuntimeExceptionRegex() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorNoSniffsTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorNoSniffsTest.xml new file mode 100644 index 00000000..cc61e3c5 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorNoSniffsTest.xml @@ -0,0 +1,6 @@ + + + + . + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorTest.php new file mode 100644 index 00000000..eaea6c23 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorTest.php @@ -0,0 +1,293 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Autoload; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test various aspects of the Ruleset::__construct() method not covered via other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::__construct + */ +final class ConstructorTest extends AbstractRulesetTestCase +{ + + + /** + * Test setting the ruleset name. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param string $expected The expected set ruleset name. + * + * @dataProvider dataHandlingStandardsPassedViaCLI + * + * @return void + */ + public function testHandlingStandardsPassedViaCLI($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + $ruleset = new Ruleset($config); + + $this->assertSame($expected, $ruleset->name); + + }//end testHandlingStandardsPassedViaCLI() + + + /** + * Data provider. + * + * @see testHandlingStandardsPassedViaCLI() + * + * @return array>> + */ + public static function dataHandlingStandardsPassedViaCLI() + { + return [ + 'Single standard passed' => [ + 'cliArgs' => ['--standard=PSR1'], + 'expected' => 'PSR1', + ], + 'Multiple standards passed' => [ + 'cliArgs' => ['--standard=PSR1,Zend'], + 'expected' => 'PSR1, Zend', + ], + 'Absolute path to standard directory passed' => [ + 'cliArgs' => [ + '--standard='.__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard', + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => 'TestStandard', + ], + ]; + + }//end dataHandlingStandardsPassedViaCLI() + + + /** + * Verify that standards are registered with the Autoloader. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param array $expected Minimum set of standards expected to be registered with the autoloader. + * + * @dataProvider dataStandardsAreRegisteredWithAutoloader + * + * @return void + */ + public function testStandardsAreRegisteredWithAutoloader($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + new Ruleset($config); + + $autoloadPaths = Autoload::getSearchPaths(); + + // Note: doing a full comparison of the Autoloader registered standards would make this test unstable + // as the `CodeSniffer.conf` of the user running the tests could interfer if they have additional + // external standards registered. + // Also note that `--runtime-set` is being used to set `installed_paths` to prevent making any changes to + // the `CodeSniffer.conf` file of the user running the tests. + foreach ($expected as $path => $namespacedStandardName) { + $this->assertArrayHasKey($path, $autoloadPaths, "Path $path has not been registered with the autoloader"); + $this->assertSame($namespacedStandardName, $autoloadPaths[$path], 'Expected (namespaced) standard name does not match'); + } + + }//end testStandardsAreRegisteredWithAutoloader() + + + /** + * Data provider. + * + * @see testStandardsAreRegisteredWithAutoloader() + * + * @return array>> + */ + public static function dataStandardsAreRegisteredWithAutoloader() + { + $basePath = dirname(dirname(dirname(__DIR__))).DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Standards'.DIRECTORY_SEPARATOR; + $defaultPaths = [ + $basePath.'MySource' => 'MySource', + $basePath.'PEAR' => 'PEAR', + $basePath.'PSR1' => 'PSR1', + $basePath.'PSR12' => 'PSR12', + $basePath.'PSR2' => 'PSR2', + $basePath.'Squiz' => 'Squiz', + $basePath.'Zend' => 'Zend', + ]; + + $data = [ + 'Default standards' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--runtime-set installed_paths .', + ], + 'expected' => $defaultPaths, + ], + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'DirectoryExpansion'; + $extraInstalledPath .= DIRECTORY_SEPARATOR.'.hiddenAbove'.DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'MyStandard'; + $data['Additional non-namespaced standard'] = [ + 'cliArgs' => [ + '--standard=MyStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'MyStandard']), + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard'; + $data['Additional namespaced standard'] = [ + 'cliArgs' => [ + '--standard=TestStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'Fixtures\TestStandard']), + ]; + + return $data; + + }//end dataStandardsAreRegisteredWithAutoloader() + + + /** + * Verify handling of sniff restrictions in combination with the caching setting. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param bool $cache Whether to turn the cache on or off. + * @param array $expected Sniffs which are expected to have been registered. + * + * @dataProvider dataCachingVersusRestrictions + * + * @return void + */ + public function testCachingVersusRestrictions($cliArgs, $cache, $expected) + { + $config = new ConfigDouble($cliArgs); + + // Overrule the cache setting (which is being ignored in the Config when the tests are running). + $config->cache = $cache; + + $ruleset = new Ruleset($config); + + $actual = array_keys($ruleset->sniffs); + sort($actual); + + $this->assertSame($expected, $actual); + + }//end testCachingVersusRestrictions() + + + /** + * Data provider. + * + * Note: the test cases only use `--exclude` to restrict, + * + * @see testCachingVersusRestrictions() + * + * @return array>> + */ + public static function dataCachingVersusRestrictions() + { + $completeSet = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ]; + + return [ + 'No restrictions, cache off' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => false, + 'expected' => $completeSet, + ], + 'Has exclusions, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ], + ], + 'Has sniff selection, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--sniffs=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + ], + ], + 'No restrictions, cache on' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => true, + 'expected' => $completeSet, + ], + 'Has exclusions, cache on' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowAlternativePHPTags,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects', + ], + 'cache' => true, + 'expected' => $completeSet, + ], + + /* + * "Has sniff selection, cache on" case cannot be tested due to the `Ruleset` class + * containing special handling of sniff selection when the tests are running. + */ + + ]; + + }//end dataCachingVersusRestrictions() + + + /** + * Test an exception is thrown when no sniffs have been registered via the ruleset. + * + * @return void + */ + public function testNoSniffsRegisteredException() + { + $standard = __DIR__.'/ConstructorNoSniffsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $message = 'ERROR: No sniffs were registered.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testNoSniffsRegisteredException() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/DisplayCachedMessagesTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/DisplayCachedMessagesTest.php new file mode 100644 index 00000000..55b0b708 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/DisplayCachedMessagesTest.php @@ -0,0 +1,312 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; +use PHP_CodeSniffer\Util\MessageCollector; +use ReflectionMethod; +use ReflectionProperty; + +/** + * Test error handling for the Ruleset. + * + * Note: this is purely a unit test of the `displayCachedMessages()` method. + * The errors themselves are mocked. + * + * @covers \PHP_CodeSniffer\Ruleset::displayCachedMessages + */ +final class DisplayCachedMessagesTest extends AbstractRulesetTestCase +{ + + + /** + * Test that no exception nor output is generated when there are no cached messsages. + * + * @return void + */ + public function testDisplayCachedMessagesStaysSilentWithoutErrors() + { + $ruleset = $this->getPlainRuleset(); + + $this->expectOutputString(''); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testDisplayCachedMessagesStaysSilentWithoutErrors() + + + /** + * Verify that blocking errors encountered while loading the ruleset(s) result in an exception being thrown. + * + * @param array $messages The messages encountered. + * @param string $expected The expected function output to screen (via an internally handled exception). + * + * @dataProvider dataBlockingErrorsAreDisplayedViaAnException + * + * @return void + */ + public function testBlockingErrorsAreDisplayedViaAnException($messages, $expected) + { + $ruleset = $this->getPlainRuleset(); + $this->mockCachedMessages($ruleset, $messages); + + $this->expectRuntimeExceptionMessage($expected); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testBlockingErrorsAreDisplayedViaAnException() + + + /** + * Data provider. + * + * @see testBlockingErrorsAreDisplayedViaAnException() + * + * @return array>> + */ + public static function dataBlockingErrorsAreDisplayedViaAnException() + { + return [ + 'One error' => [ + 'messages' => ['This is a serious blocking issue' => MessageCollector::ERROR], + 'expected' => 'ERROR: This is a serious blocking issue'.PHP_EOL.PHP_EOL, + ], + 'Multiple blocking errors' => [ + 'messages' => [ + 'This is a serious blocking issue' => MessageCollector::ERROR, + 'And here is another one' => MessageCollector::ERROR, + 'OMG, why do you think that would work ?' => MessageCollector::ERROR, + ], + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + 'expected' => 'ERROR: This is a serious blocking issue'.PHP_EOL + . 'ERROR: And here is another one'.PHP_EOL + . 'ERROR: OMG, why do you think that would work ?'.PHP_EOL.PHP_EOL, + // phpcs:enable + ], + 'Mix of blocking and non-blocking errors' => [ + 'messages' => [ + 'This is a serious blocking issue' => MessageCollector::ERROR, + 'Something something deprecated and will be removed in v x.x.x' => MessageCollector::DEPRECATED, + 'Careful, this may not be correct' => MessageCollector::NOTICE, + ], + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + 'expected' => 'ERROR: This is a serious blocking issue'.PHP_EOL + . 'NOTICE: Careful, this may not be correct'.PHP_EOL + . 'DEPRECATED: Something something deprecated and will be removed in v x.x.x'.PHP_EOL.PHP_EOL, + // phpcs:enable + ], + ]; + + }//end dataBlockingErrorsAreDisplayedViaAnException() + + + /** + * Test display of non-blocking messages encountered while loading the ruleset(s). + * + * @param array $messages The messages encountered. + * @param string $expected The expected function output to screen. + * + * @dataProvider dataNonBlockingErrorsGenerateOutput + * + * @return void + */ + public function testNonBlockingErrorsGenerateOutput($messages, $expected) + { + $ruleset = $this->getPlainRuleset(); + $this->mockCachedMessages($ruleset, $messages); + + $this->expectOutputString($expected); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testNonBlockingErrorsGenerateOutput() + + + /** + * Data provider. + * + * @see testNonBlockingErrorsGenerateOutput() + * + * @return array>> + */ + public static function dataNonBlockingErrorsGenerateOutput() + { + return [ + 'One deprecation' => [ + 'messages' => ['My deprecation message' => MessageCollector::DEPRECATED], + 'expected' => 'DEPRECATED: My deprecation message'.PHP_EOL.PHP_EOL, + ], + 'One notice' => [ + 'messages' => ['My notice message' => MessageCollector::NOTICE], + 'expected' => 'NOTICE: My notice message'.PHP_EOL.PHP_EOL, + ], + 'One warning' => [ + 'messages' => ['My warning message' => MessageCollector::WARNING], + 'expected' => 'WARNING: My warning message'.PHP_EOL.PHP_EOL, + ], + 'Multiple non-blocking errors' => [ + 'messages' => [ + 'Something something deprecated and will be removed in v x.x.x' => MessageCollector::DEPRECATED, + 'Something is not supported and support may be removed' => MessageCollector::WARNING, + 'Some other deprecation notice' => MessageCollector::DEPRECATED, + 'Careful, this may not be correct' => MessageCollector::NOTICE, + ], + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + 'expected' => 'WARNING: Something is not supported and support may be removed'.PHP_EOL + .'NOTICE: Careful, this may not be correct'.PHP_EOL + .'DEPRECATED: Something something deprecated and will be removed in v x.x.x'.PHP_EOL + .'DEPRECATED: Some other deprecation notice'.PHP_EOL.PHP_EOL, + // phpcs:enable + ], + ]; + + }//end dataNonBlockingErrorsGenerateOutput() + + + /** + * Test that blocking errors will always show, independently of specific command-line options being used. + * + * @param array $configArgs Arguments to pass to the Config. + * + * @dataProvider dataSelectiveDisplayOfMessages + * + * @return void + */ + public function testBlockingErrorsAlwaysShow($configArgs) + { + $config = new ConfigDouble($configArgs); + $ruleset = new Ruleset($config); + + $message = 'Some serious error'; + $errors = [$message => MessageCollector::ERROR]; + $this->mockCachedMessages($ruleset, $errors); + + $this->expectRuntimeExceptionMessage('ERROR: '.$message.PHP_EOL); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testBlockingErrorsAlwaysShow() + + + /** + * Test that non-blocking messsages will not show when specific command-line options are being used. + * + * @param array $configArgs Arguments to pass to the Config. + * + * @dataProvider dataSelectiveDisplayOfMessages + * + * @return void + */ + public function testNonBlockingErrorsDoNotShowUnderSpecificCircumstances($configArgs) + { + $config = new ConfigDouble($configArgs); + $ruleset = new Ruleset($config); + $this->mockCachedMessages($ruleset, ['Deprecation notice' => MessageCollector::DEPRECATED]); + + $this->expectOutputString(''); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testNonBlockingErrorsDoNotShowUnderSpecificCircumstances() + + + /** + * Data provider. + * + * @see testBlockingErrorsAlwaysShow() + * @see testNonBlockingErrorsDoNotShow() + * + * @return array>> + */ + public static function dataSelectiveDisplayOfMessages() + { + $data = [ + 'Explain mode' => [ + 'configArgs' => ['-e'], + ], + 'Quiet mode' => [ + 'configArgs' => ['-q'], + ], + ]; + + // Setting the `--generator` arg is only supported when running `phpcs`. + if (PHP_CODESNIFFER_CBF === false) { + $data['Documentation is requested'] = [ + 'configArgs' => ['--generator=text'], + ]; + } + + return $data; + + }//end dataSelectiveDisplayOfMessages() + + + /** + * Test Helper. + * + * @return \PHP_CodeSniffer\Ruleset + */ + private function getPlainRuleset() + { + static $ruleset; + + if (isset($ruleset) === false) { + $config = new ConfigDouble(); + $ruleset = new Ruleset($config); + } + + return $ruleset; + + }//end getPlainRuleset() + + + /** + * Add mock messages to the message cache. + * + * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset object. + * @param array $messages The messages to add to the message cache. + * + * @return void + */ + private function mockCachedMessages(Ruleset $ruleset, $messages) + { + $reflProperty = new ReflectionProperty($ruleset, 'msgCache'); + $reflProperty->setAccessible(true); + + $msgCache = $reflProperty->getValue($ruleset); + foreach ($messages as $msg => $type) { + $msgCache->add($msg, $type); + } + + $reflProperty->setAccessible(false); + + }//end mockCachedMessages() + + + /** + * Invoke the display of the cached messages. + * + * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset object. + * + * @return void + */ + private function invokeDisplayCachedMessages(Ruleset $ruleset) + { + $reflMethod = new ReflectionMethod($ruleset, 'displayCachedMessages'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($ruleset); + $reflMethod->setAccessible(false); + + }//end invokeDisplayCachedMessages() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch1Test.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch1Test.xml new file mode 100644 index 00000000..e72c4b9d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch1Test.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch2Test.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch2Test.xml new file mode 100644 index 00000000..a1013749 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch2Test.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathFailTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathFailTest.xml new file mode 100644 index 00000000..5298b54a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathFailTest.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.php new file mode 100644 index 00000000..10a4dd98 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.php @@ -0,0 +1,121 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test home path handling in the Ruleset::expandRulesetReference() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandRulesetReference + */ +final class ExpandRulesetReferenceHomePathTest extends AbstractRulesetTestCase +{ + + /** + * Original value of the user's home path environment variable. + * + * @var string|false Path or false is the `HOME` environment variable is not available. + */ + private static $homepath = false; + + + /** + * Store the user's home path. + * + * @beforeClass + * + * @return void + */ + public static function storeHomePath() + { + self::$homepath = getenv('HOME'); + + }//end storeHomePath() + + + /** + * Restore the user's home path environment variable in case the test changed it or created it. + * + * @afterClass + * + * @return void + */ + public static function restoreHomePath() + { + if (is_string(self::$homepath) === true) { + putenv('HOME='.self::$homepath); + } else { + // Remove the environment variable as it didn't exist before. + putenv('HOME'); + } + + }//end restoreHomePath() + + + /** + * Set the home path to an alternative location. + * + * @before + * + * @return void + */ + protected function setHomePath() + { + $fakeHomePath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'FakeHomePath'; + putenv("HOME=$fakeHomePath"); + + }//end setHomePath() + + + /** + * Verify that a sniff reference with the magic "home path" placeholder gets expanded correctly + * and finds sniffs if the path exists underneath the "home path". + * + * @return void + */ + public function testHomePathRefGetsExpandedAndFindsSniff() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceHomePathTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['MyStandard.Category.Valid' => 'FakeHomePath\\MyStandard\\Sniffs\\Category\\ValidSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testHomePathRefGetsExpandedAndFindsSniff() + + + /** + * Verify that a sniff reference with the magic "home path" placeholder gets expanded correctly + * and still fails to find sniffs if the path doesn't exists underneath the "home path". + * + * @return void + */ + public function testHomePathRefGetsExpandedAndThrowsExceptionWhenPathIsInvalid() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceHomePathFailTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $exceptionMessage = 'ERROR: Referenced sniff "~/src/MyStandard/Sniffs/DoesntExist/" does not exist.'.PHP_EOL; + $exceptionMessage .= 'ERROR: No sniffs were registered.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($exceptionMessage); + + new Ruleset($config); + + }//end testHomePathRefGetsExpandedAndThrowsExceptionWhenPathIsInvalid() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.xml new file mode 100644 index 00000000..e21f2a6e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalIgnoreTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalIgnoreTest.xml new file mode 100644 index 00000000..edd9b1e8 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalIgnoreTest.xml @@ -0,0 +1,15 @@ + + + + + + + 0 + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalStandardTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalStandardTest.xml new file mode 100644 index 00000000..d01c68cf --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalStandardTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalTest.php new file mode 100644 index 00000000..5f0180da --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalTest.php @@ -0,0 +1,71 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of "internal" references in the Ruleset::expandRulesetReference() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandRulesetReference + */ +final class ExpandRulesetReferenceInternalTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that a ruleset reference starting with "Internal." (including the dot) doesn't cause any sniffs to be registered. + * + * @return void + */ + public function testInternalRefDoesNotGetExpanded() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceInternalIgnoreTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\BacktickOperatorSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testInternalRefDoesNotGetExpanded() + + + /** + * While definitely not recommended, including a standard named "Internal", _does_ allow for sniffs to be registered. + * + * Note: customizations (exclusions/property setting etc) for individual sniffs may not always be handled correctly, + * which is why naming a standard "Internal" is definitely not recommended. + * + * @return void + */ + public function testInternalStandardDoesGetExpanded() + { + $message = 'DEPRECATED: The name "Internal" is reserved for internal use. A PHP_CodeSniffer standard should not be called "Internal".'.PHP_EOL; + $message .= 'Contact the maintainer of the standard to fix this.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($message); + + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceInternalStandardTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Internal.Valid.Valid' => 'Fixtures\\Internal\\Sniffs\\Valid\\ValidSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testInternalStandardDoesGetExpanded() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode1Test.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode1Test.xml new file mode 100644 index 00000000..a5531bda --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode1Test.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode2Test.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode2Test.xml new file mode 100644 index 00000000..c18ba25c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode2Test.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode3Test.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode3Test.xml new file mode 100644 index 00000000..46ac2641 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode3Test.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidHomePathRefTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidHomePathRefTest.xml new file mode 100644 index 00000000..349449ed --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidHomePathRefTest.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceMissingFileTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceMissingFileTest.xml new file mode 100644 index 00000000..18e8c390 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceMissingFileTest.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.php new file mode 100644 index 00000000..284bdf7f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.php @@ -0,0 +1,134 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test various aspects of the Ruleset::expandRulesetReference() method not covered by other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::expandRulesetReference + */ +final class ExpandRulesetReferenceTest extends AbstractRulesetTestCase +{ + + + /** + * Test handling of path references relative to the originally included ruleset. + * + * @return void + */ + public function testRulesetRelativePathReferences() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = [ + 'ExternalA.CheckSomething.Valid' => 'Fixtures\\ExternalA\\Sniffs\\CheckSomething\\ValidSniff', + 'TestStandard.ValidSniffs.RegisterEmptyArray' => 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff', + 'ExternalB.CheckMore.Valid' => 'Fixtures\\ExternalB\\Sniffs\\CheckMore\\ValidSniff', + ]; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testRulesetRelativePathReferences() + + + /** + * Test that an exception is thrown if a ruleset contains an unresolvable reference. + * + * @param string $standard The standard to use for the test. + * @param string $replacement The reference which will be used in the exception message. + * + * @dataProvider dataUnresolvableReferenceThrowsException + * + * @return void + */ + public function testUnresolvableReferenceThrowsException($standard, $replacement) + { + // Set up the ruleset. + $standard = __DIR__.'/'.$standard; + $config = new ConfigDouble(["--standard=$standard"]); + + $exceptionMessage = 'ERROR: Referenced sniff "%s" does not exist.'.PHP_EOL; + $exceptionMessage .= 'ERROR: No sniffs were registered.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage(sprintf($exceptionMessage, $replacement)); + + new Ruleset($config); + + }//end testUnresolvableReferenceThrowsException() + + + /** + * Data provider. + * + * @see testUnresolvableReferenceThrowsException() + * + * @return array> + */ + public static function dataUnresolvableReferenceThrowsException() + { + $data = [ + 'Referencing a non-existent XML file' => [ + 'standard' => 'ExpandRulesetReferenceMissingFileTest.xml', + 'replacement' => './MissingFile.xml', + ], + 'Referencing an invalid directory starting with "~"' => [ + 'standard' => 'ExpandRulesetReferenceInvalidHomePathRefTest.xml', + 'replacement' => '~/src/Standards/Squiz/Sniffs/Files/', + ], + 'Referencing an unknown standard' => [ + 'standard' => 'ExpandRulesetReferenceUnknownStandardTest.xml', + 'replacement' => 'UnknownStandard', + ], + 'Referencing a non-existent category in a known standard' => [ + 'standard' => 'ExpandRulesetReferenceUnknownCategoryTest.xml', + 'replacement' => 'TestStandard.UnknownCategory', + ], + 'Referencing a non-existent sniff in a known standard' => [ + 'standard' => 'ExpandRulesetReferenceUnknownSniffTest.xml', + 'replacement' => 'TestStandard.InvalidSniffs.UnknownRule', + ], + 'Referencing an invalid error code - no standard name' => [ + 'standard' => 'ExpandRulesetReferenceInvalidErrorCode1Test.xml', + 'replacement' => '.Invalid.Undetermined.Found', + ], + 'Referencing an invalid error code - no category name' => [ + 'standard' => 'ExpandRulesetReferenceInvalidErrorCode2Test.xml', + 'replacement' => 'Standard..Undetermined.Found', + ], + 'Referencing an invalid error code - no sniff name' => [ + 'standard' => 'ExpandRulesetReferenceInvalidErrorCode3Test.xml', + 'replacement' => 'Standard.Invalid..Found', + ], + ]; + + // Add tests which are only relevant for case-sensitive OSes. + if (stripos(PHP_OS, 'WIN') === false) { + $data['Referencing an existing sniff, but there is a case mismatch (OS-dependent) [1]'] = [ + 'standard' => 'ExpandRulesetReferenceCaseMismatch1Test.xml', + 'replacement' => 'psr12.functions.nullabletypedeclaration', + ]; + $data['Referencing an existing sniff, but there is a case mismatch (OS-dependent) [2]'] = [ + 'standard' => 'ExpandRulesetReferenceCaseMismatch2Test.xml', + 'replacement' => 'PSR12.Functions.ReturntypeDeclaration', + ]; + } + + return $data; + + }//end dataUnresolvableReferenceThrowsException() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.xml new file mode 100644 index 00000000..f3147c5e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownCategoryTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownCategoryTest.xml new file mode 100644 index 00000000..17ec1a7b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownCategoryTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownSniffTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownSniffTest.xml new file mode 100644 index 00000000..8cff25e1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownSniffTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownStandardTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownStandardTest.xml new file mode 100644 index 00000000..c8b56b10 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownStandardTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.php new file mode 100644 index 00000000..ddd3a514 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.php @@ -0,0 +1,67 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::expandSniffDirectory() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandSniffDirectory + */ +final class ExpandSniffDirectoryTest extends TestCase +{ + + + /** + * Test finding sniff files based on a given directory. + * + * This test verifies that: + * - Hidden (sub)directories are ignored, but the given directory is allowed to be within a hidden directory. + * - Hidden files are ignored. + * - Files without a "php" extension are ignored. + * - Files without a "Sniff" suffix in the file name are ignored. + * + * Note: the "[Another]AbstractSniff" files will be found and included in the return value + * from `Ruleset::expandSniffDirectory()`. + * Those are filtered out later in the `Ruleset::registerSniffs()` method. + * + * @return void + */ + public function testExpandSniffDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandSniffDirectoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expectedPathToRuleset = __DIR__.'/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/ruleset.xml'; + $expectedPathToRuleset = realpath($expectedPathToRuleset); + $this->assertNotFalse($expectedPathToRuleset, 'Ruleset file could not be found'); + $this->assertContains($expectedPathToRuleset, $ruleset->paths, 'Ruleset file not included in the "seen ruleset paths"'); + + $expectedSniffCodes = [ + 'MyStandard.CategoryA.FindMe' => 'MyStandard\\Sniffs\\CategoryA\\FindMeSniff', + 'MyStandard.CategoryB.FindMe' => 'MyStandard\\Sniffs\\CategoryB\\FindMeSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expectedSniffCodes, $actual, 'Registered sniffs do not match expectation'); + + }//end testExpandSniffDirectory() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml new file mode 100644 index 00000000..158805e5 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/BrokenNamingConventions/Sniffs/Category/Sniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/BrokenNamingConventions/Sniffs/Category/Sniff.php new file mode 100644 index 00000000..9da190d1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/BrokenNamingConventions/Sniffs/Category/Sniff.php @@ -0,0 +1,24 @@ + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalA/Sniffs/CheckSomething/ValidSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalA/Sniffs/CheckSomething/ValidSniff.php new file mode 100644 index 00000000..51061e3b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalA/Sniffs/CheckSomething/ValidSniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalB/Sniffs/CheckMore/ValidSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalB/Sniffs/CheckMore/ValidSniff.php new file mode 100644 index 00000000..1584f705 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalB/Sniffs/CheckMore/ValidSniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/FakeHomePath/src/MyStandard/Sniffs/Category/ValidSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/FakeHomePath/src/MyStandard/Sniffs/Category/ValidSniff.php new file mode 100644 index 00000000..9346df9e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/FakeHomePath/src/MyStandard/Sniffs/Category/ValidSniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Internal/Sniffs/Valid/ValidSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Internal/Sniffs/Valid/ValidSniff.php new file mode 100644 index 00000000..e7a04f49 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Internal/Sniffs/Valid/ValidSniff.php @@ -0,0 +1,25 @@ + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs new file mode 100644 index 00000000..e69de29b diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml new file mode 100644 index 00000000..5b0897c4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml @@ -0,0 +1,4 @@ + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php new file mode 100644 index 00000000..2b1fadaf --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php @@ -0,0 +1,8 @@ +string,10=>10,float=>1.5,null=>null,true=>true,false=>false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsEmptyArray[] + +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolArrayWithOnlyValues[] string, 10, 1.5, null, true, false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolArrayWithKeysAndValues[] string=>string,10=>10,float=>1.5,null=>null,true=>true,false=>false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolEmptyArray[] + +echo 'hello!'; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php new file mode 100644 index 00000000..659d89ee --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php @@ -0,0 +1,41 @@ +magic[$name] = $value; + } + + public function __get($name) + { + if (isset($this->magic[$name])) { + return $this->magic[$name]; + } + + return null; + } + + public function register() + { + return [T_WHITESPACE]; + } + + public function process(File $phpcsFile, $stackPtr) + { + // Do something. + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php new file mode 100644 index 00000000..0f58b2e0 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php @@ -0,0 +1,26 @@ + + */ + public $expectsArrayWithOnlyValues; + + /** + * Used to verify that array properties with keys get parsed to a proper array. + * + * @var array + */ + public $expectsArrayWithKeysAndValues; + + /** + * Used to verify that array properties can get extended. + * + * @var array + */ + public $expectsArrayWithExtendedValues; + + /** + * Used to verify that array properties can get extended. + * + * @var array + */ + public $expectsArrayWithExtendedKeysAndValues; + + /** + * Used to verify that array properties allow for setting a property to an empty array. + * + * @var array + */ + public $expectsEmptyArray; + + /** + * Used to verify that array properties passed as a string get parsed to a proper array. + * + * @var array + */ + public $expectsOldSchoolArrayWithOnlyValues; + + /** + * Used to verify that array properties passed as a string with keys get parsed to a proper array. + * + * @var array + */ + public $expectsOldSchoolArrayWithKeysAndValues; + + /** + * Used to verify that array properties passed as a string can get extended. + * + * @var array + */ + public $expectsOldSchoolArrayWithExtendedValues; + + /** + * Used to verify that array properties passed as a string can get extended. + * + * @var array + */ + public $expectsOldSchoolArrayWithExtendedKeysAndValues; + + /** + * Used to verify that array properties passed as a string allow for setting a property to an empty array. + * + * @var array + */ + public $expectsOldSchoolEmptyArray; + + public function register() + { + return [T_ECHO]; + } + + public function process(File $phpcsFile, $stackPtr) + { + // Do something. + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SupportedTokenizers/ImplementsDeprecatedInterfaceSniff.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SupportedTokenizers/ImplementsDeprecatedInterfaceSniff.php new file mode 100644 index 00000000..af095072 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SupportedTokenizers/ImplementsDeprecatedInterfaceSniff.php @@ -0,0 +1,46 @@ + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.php new file mode 100644 index 00000000..ae6b8bea --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::getIgnorePatterns() method. + * + * @covers \PHP_CodeSniffer\Ruleset::getIgnorePatterns + */ +final class GetIgnorePatternsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $standard = __DIR__."/GetIgnorePatternsTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + + }//end initializeConfigAndRuleset() + + + /** + * Test retrieving ignore patterns. + * + * @param string|null $listener The listener to get patterns for or null for all patterns. + * @param array> $expected The expected function output. + * + * @dataProvider dataGetIgnorePatterns + * + * @return void + */ + public function testGetIgnorePatterns($listener, $expected) + { + $this->assertSame($expected, self::$ruleset->getIgnorePatterns($listener)); + + }//end testGetIgnorePatterns() + + + /** + * Data provider. + * + * @see self::testGetIgnorePatterns() + * + * @return array>|null>> + */ + public static function dataGetIgnorePatterns() + { + return [ + 'All ignore patterns' => [ + 'listener' => null, + 'expected' => [ + 'PSR1.Classes.ClassDeclaration' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + 'Generic.Formatting.SpaceAfterCast' => [ + './src/*/test\\.php$' => 'absolute', + ], + './tests/' => 'absolute', + './vendor/*' => 'absolute', + '*/node-modules/*' => 'relative', + ], + ], + 'Ignore patterns for PSR1.Classes.ClassDeclaration' => [ + 'listener' => 'PSR1.Classes.ClassDeclaration', + 'expected' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + ], + 'Ignore patterns for Generic.Formatting.SpaceAfterCast' => [ + 'listener' => 'Generic.Formatting.SpaceAfterCast', + 'expected' => ['./src/*/test\\.php$' => 'absolute'], + ], + 'Ignore patterns for sniff without ignore patterns' => [ + 'listener' => 'PSR1.Files.SideEffects', + 'expected' => [], + ], + ]; + + }//end dataGetIgnorePatterns() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.xml new file mode 100644 index 00000000..a0496c80 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.xml @@ -0,0 +1,19 @@ + + + + ./tests/ + ./vendor/* + */node-modules/* + + + + + ./src/*/file.php + ./bin/ + + + + ./src/*/test\.php$ + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.php new file mode 100644 index 00000000..a38401b6 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.php @@ -0,0 +1,108 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::getIncludePatterns() method. + * + * @covers \PHP_CodeSniffer\Ruleset::getIncludePatterns + */ +final class GetIncludePatternsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $standard = __DIR__."/GetIncludePatternsTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + + }//end initializeConfigAndRuleset() + + + /** + * Test retrieving include patterns. + * + * @param string|null $listener The listener to get patterns for or null for all patterns. + * @param array> $expected The expected function output. + * + * @dataProvider dataGetIncludePatterns + * + * @return void + */ + public function testGetIncludePatterns($listener, $expected) + { + $this->assertSame($expected, self::$ruleset->getIncludePatterns($listener)); + + }//end testGetIncludePatterns() + + + /** + * Data provider. + * + * @see self::testGetIncludePatterns() + * + * @return array>|null>> + */ + public static function dataGetIncludePatterns() + { + return [ + 'All include patterns' => [ + 'listener' => null, + 'expected' => [ + 'PSR1.Classes.ClassDeclaration' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + 'Generic.Formatting.SpaceAfterCast' => [ + './src/*/test\\.php$' => 'absolute', + ], + ], + ], + 'Include patterns for PSR1.Classes.ClassDeclaration' => [ + 'listener' => 'PSR1.Classes.ClassDeclaration', + 'expected' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + ], + 'Include patterns for Generic.Formatting.SpaceAfterCast' => [ + 'listener' => 'Generic.Formatting.SpaceAfterCast', + 'expected' => ['./src/*/test\\.php$' => 'absolute'], + ], + 'Include patterns for sniff without include patterns' => [ + 'listener' => 'PSR1.Files.SideEffects', + 'expected' => [], + ], + ]; + + }//end dataGetIncludePatterns() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.xml new file mode 100644 index 00000000..e59c8991 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.xml @@ -0,0 +1,15 @@ + + + + + + + ./src/*/file.php + ./bin/ + + + + ./src/*/test\.php$ + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.php new file mode 100644 index 00000000..d9384052 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.php @@ -0,0 +1,82 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test handling of sniffs not following the PHPCS naming conventions in the Ruleset::populateTokenListeners() method. + * + * @covers \PHP_CodeSniffer\Ruleset::populateTokenListeners + */ +final class PopulateTokenListenersNamingConventionsTest extends TestCase +{ + + + /** + * Verify a warning is shown for sniffs not complying with the PHPCS naming conventions. + * + * Including sniffs which do not comply with the PHPCS naming conventions is soft deprecated since + * PHPCS 3.12.0, hard deprecated since PHPCS 3.13.0 and support will be removed in PHPCS 4.0.0. + * + * @return void + */ + public function testBrokenNamingConventions() + { + // Set up the ruleset. + $standard = __DIR__.'/PopulateTokenListenersNamingConventionsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // The "Generic.PHP.BacktickOperator" sniff is the only valid sniff. + $expectedSniffCodes = [ + '..NoNamespace' => 'NoNamespaceSniff', + '.Sniffs.MissingCategoryDir' => 'BrokenNamingConventions\\Sniffs\\MissingCategoryDirSniff', + '.Sniffs.PartialNamespace' => 'Sniffs\\PartialNamespaceSniff', + 'BrokenNamingConventions.Category.' => 'BrokenNamingConventions\\Sniffs\\Category\\Sniff', + 'BrokenNamingConventions.Sniffs.CategoryCalledSniffs' => 'BrokenNamingConventions\\Sniffs\\Sniffs\\CategoryCalledSniffsSniff', + 'Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\BacktickOperatorSniff', + 'Sniffs.SubDir.TooDeeplyNested' => 'BrokenNamingConventions\\Sniffs\\Category\\SubDir\\TooDeeplyNestedSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expectedSniffCodes, $actual, 'Registered sniffs do not match expectation'); + + $expectedMessage = 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\MissingCategoryDirSniff does not comply'; + $expectedMessage .= ' with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff NoNamespaceSniff does not comply with the PHP_CodeSniffer naming conventions.'; + $expectedMessage .= ' This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff Sniffs\\PartialNamespaceSniff does not comply with the PHP_CodeSniffer naming conventions.'; + $expectedMessage .= ' This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\Category\\Sniff does not comply'; + $expectedMessage .= ' with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\Sniffs\\CategoryCalledSniffsSniff does not'; + $expectedMessage .= ' comply with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\Category\\SubDir\\TooDeeplyNestedSniff'; + $expectedMessage .= ' does not comply with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($expectedMessage); + + }//end testBrokenNamingConventions() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.xml new file mode 100644 index 00000000..58e54a92 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml new file mode 100644 index 00000000..23c59c00 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.php new file mode 100644 index 00000000..87e6da80 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.php @@ -0,0 +1,111 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test the Ruleset::populateTokenListeners() method shows a deprecation notice for sniffs supporting JS and/or CSS tokenizers. + * + * @covers \PHP_CodeSniffer\Ruleset::populateTokenListeners + */ +final class PopulateTokenListenersSupportedTokenizersTest extends AbstractRulesetTestCase +{ + + /** + * The Config object. + * + * @var \PHP_CodeSniffer\Config + */ + private static $config; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfig() + { + // Set up the ruleset. + $standard = __DIR__.'/PopulateTokenListenersSupportedTokenizersTest.xml'; + self::$config = new ConfigDouble(["--standard=$standard"]); + + }//end initializeConfig() + + + /** + * Verify that a deprecation notice is shown if a non-deprecated sniff supports the JS/CSS tokenizer(s). + * + * Additionally, this test verifies that: + * - No deprecation notice is thrown if the complete sniff is deprecated. + * - No deprecation notice is thrown when the sniff _also_ supports PHP. + * - No deprecation notice is thrown when no tokenizers are supported (not sure why anyone would do that, but :shrug:). + * + * {@internal The test uses a data provider to verify the messages as the _order_ of the messages depends + * on the OS on which the tests are run (order in which files are retrieved), which makes the order within the + * complete message too unpredictable to test in one go.} + * + * @param string $expected The expected message output in regex format. + * + * @dataProvider dataDeprecatedTokenizersTriggerDeprecationNotice + * + * @return void + */ + public function testDeprecatedTokenizersTriggerDeprecationNotice($expected) + { + $this->expectOutputRegex($expected); + + new Ruleset(self::$config); + + }//end testDeprecatedTokenizersTriggerDeprecationNotice() + + + /** + * Data provider. + * + * @see testDeprecatedTokenizersTriggerDeprecationNotice() + * + * @return array> + */ + public static function dataDeprecatedTokenizersTriggerDeprecationNotice() + { + $cssJsDeprecated = '`DEPRECATED: Scanning CSS/JS files is deprecated and support will be removed in PHP_CodeSniffer 4\.0\.\R'; + $cssJsDeprecated .= 'The %1$s sniff is listening for %2$s\.\R`'; + + $customTokenizer = '`DEPRECATED: Support for custom tokenizers will be removed in PHP_CodeSniffer 4\.0\.\R'; + $customTokenizer .= 'The %1$s sniff is listening for %2$s\.\R`'; + + return [ + 'Listens for CSS' => [ + 'expected' => sprintf($cssJsDeprecated, 'TestStandard.SupportedTokenizers.ListensForCSS', 'CSS'), + ], + 'Listens for JS' => [ + 'expected' => sprintf($cssJsDeprecated, 'TestStandard.SupportedTokenizers.ListensForJS', 'JS'), + ], + 'Listens for both CSS and JS' => [ + 'expected' => sprintf($cssJsDeprecated, 'TestStandard.SupportedTokenizers.ListensForCSSAndJS', 'CSS, JS'), + ], + 'Listens for CSS and something unrecognized' => [ + 'expected' => sprintf($cssJsDeprecated, 'TestStandard.SupportedTokenizers.ListensForCSSAndUnrecognized', 'CSS, Unrecognized'), + ], + 'Listens for only unrecognized tokenizers' => [ + 'expected' => sprintf($customTokenizer, 'TestStandard.SupportedTokenizers.ListensForUnrecognizedTokenizers', 'SCSS, TypeScript'), + ], + ]; + + }//end dataDeprecatedTokenizersTriggerDeprecationNotice() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.xml new file mode 100644 index 00000000..377cb2f6 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.php new file mode 100644 index 00000000..347ffdde --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.php @@ -0,0 +1,553 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; +use PHP_CodeSniffer\Util\Tokens; +use ReflectionObject; +use ReflectionProperty; + +/** + * Test the Ruleset::populateTokenListeners() method. + * + * @covers \PHP_CodeSniffer\Ruleset::populateTokenListeners + */ +final class PopulateTokenListenersTest extends AbstractRulesetTestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test only once (but do allow recording code coverage). + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PopulateTokenListenersTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Test an exception is thrown when the register() method of a sniff doesn't return an array. + * + * @return void + */ + public function testSniffWhereRegisterDoesNotReturnAnArrayThrowsException() + { + $standard = __DIR__.'/PopulateTokenListenersRegisterNoArrayTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $sniffClass = 'Fixtures\\TestStandard\\Sniffs\\InvalidSniffs\\RegisterNoArraySniff'; + $message = "ERROR: The sniff {$sniffClass}::register() method must return an array.".PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + // Verify that the sniff has not been registered/has been unregistered. + // These assertions will only take effect for PHPUnit 10+. + $this->assertArrayNotHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass is listed in registered sniffs"); + $this->assertArrayNotHasKey('TestStandard.InvalidSniffs.RegisterNoArray', self::$ruleset->sniffCodes, 'Sniff code is registered'); + + }//end testSniffWhereRegisterDoesNotReturnAnArrayThrowsException() + + + /** + * Test that a sniff not registering any tokens is not listed as a listener. + * + * @return void + */ + public function testSniffWithRegisterMethodReturningEmptyArrayIsSilentlyIgnored() + { + $target = 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + $this->assertArrayNotHasKey( + $target, + $listeners, + sprintf('Found the %s sniff registered for token %s', $target, Tokens::tokenName($token)) + ); + } + + }//end testSniffWithRegisterMethodReturningEmptyArrayIsSilentlyIgnored() + + + /** + * Tests that sniffs registering tokens, will end up listening to these tokens. + * + * @param string $sniffClass The FQN for the sniff class to check. + * @param int $expectedCount Expected number of tokens to which the sniff should be listening. + * + * @dataProvider dataSniffListensToTokenss + * + * @return void + */ + public function testRegistersSniffsToListenToTokens($sniffClass, $expectedCount) + { + $counter = 0; + + foreach (self::$ruleset->tokenListeners as $listeners) { + if (isset($listeners[$sniffClass]) === true) { + ++$counter; + } + } + + $this->assertSame($expectedCount, $counter); + + }//end testRegistersSniffsToListenToTokens() + + + /** + * Data provider. + * + * @see testSniffListensToTokens() + * + * @return array> + */ + public static function dataSniffListensToTokenss() + { + return [ + 'TestStandard.SupportedTokenizers.ListensForPHPAndCSSAndJS' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\SupportedTokenizers\\ListensForPHPAndCSSAndJSSniff', + 'expectedCount' => 2, + ], + 'Generic.NamingConventions.UpperCaseConstantName' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'expectedCount' => 2, + ], + 'PSR1.Files.SideEffects' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'expectedCount' => 1, + ], + 'PSR12.ControlStructures.BooleanOperatorPlacement' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR12\\Sniffs\\ControlStructures\\BooleanOperatorPlacementSniff', + 'expectedCount' => 5, + ], + 'Squiz.ControlStructures.ForEachLoopDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'expectedCount' => 1, + ], + 'TestStandard.Deprecated.WithReplacement' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\Deprecated\\WithReplacementSniff', + 'expectedCount' => 1, + ], + 'TestStandard.ValidSniffs.RegisterEmptyArray' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff', + 'expectedCount' => 0, + ], + ]; + + }//end dataSniffListensToTokenss() + + + /** + * Test that deprecated sniffs get recognized and added to the $deprecatedSniffs list. + * + * @return void + */ + public function testRegistersWhenADeprecatedSniffIsLoaded() + { + $property = new ReflectionProperty(self::$ruleset, 'deprecatedSniffs'); + $property->setAccessible(true); + $actualValue = $property->getValue(self::$ruleset); + $property->setAccessible(false); + + // Only verify there is one deprecated sniff registered. + // There are other tests which test the deprecated sniff handling in more detail. + $this->assertTrue(is_array($actualValue)); + $this->assertCount(1, $actualValue); + + }//end testRegistersWhenADeprecatedSniffIsLoaded() + + + /** + * Verify that the setting of properties on a sniff was not triggered when there are no properties being set. + * + * @return void + */ + public function testDoesntTriggerPropertySettingForNoProperties() + { + $sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff'; + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass not listed in registered sniffs"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + $reflection = new ReflectionObject($sniffObject); + + // Just making sure there are no properties on the sniff object (which doesn't have declared properties). + $this->assertSame([], $reflection->getProperties(), "Unexpected properties found on sniff class $sniffClass"); + + }//end testDoesntTriggerPropertySettingForNoProperties() + + + /** + * Verify that the setting of properties on a sniff was triggered. + * + * @param string $sniffClass The FQN for the sniff class on which the property should be set. + * @param string $propertyName The property name. + * @param string $expected The expected property value. + * + * @dataProvider dataTriggersPropertySettingWhenPropertiesProvided + * + * @return void + */ + public function testTriggersPropertySettingWhenPropertiesProvided($sniffClass, $propertyName, $expected) + { + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass not listed in registered sniffs"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify the property has been set. + $this->assertSame($expected, $sniffObject->$propertyName, "Property on sniff class $sniffClass set to unexpected value"); + + }//end testTriggersPropertySettingWhenPropertiesProvided() + + + /** + * Data provider. + * + * @see testTriggersPropertySettingWhenPropertiesProvided() + * + * @return array> + */ + public static function dataTriggersPropertySettingWhenPropertiesProvided() + { + return [ + 'Sniff with single property being set' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR12\\Sniffs\\ControlStructures\\BooleanOperatorPlacementSniff', + 'propertyName' => 'allowOnly', + 'expected' => 'first', + ], + 'Sniff with multiple properties being set - first property' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'propertyName' => 'requiredSpacesAfterOpen', + 'expected' => '3', + ], + 'Sniff with multiple properties being set - second property' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'propertyName' => 'requiredSpacesBeforeClose', + 'expected' => '8', + ], + ]; + + }//end dataTriggersPropertySettingWhenPropertiesProvided() + + + /** + * Verifies that the "class" and "source" indexes get set. + * + * @return void + */ + public function testSetsClassAndSourceIndexes() + { + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + $this->assertArrayHasKey( + 'class', + $details, + sprintf('"tokenizers" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + $className, + $details['class'], + sprintf('Unexpected value for "class" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertArrayHasKey( + 'source', + $details, + sprintf('"source" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertTrue( + is_string($details['source']), + sprintf('Value for "source" key is not a string for token %s', Tokens::tokenName($token)) + ); + + $expected = '.'.substr($className, (strrpos($className, '\\') + 1), -5); + + $this->assertStringEndsWith( + $expected, + $details['source'], + sprintf('Unexpected value for "source" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + }//end foreach + }//end foreach + + }//end testSetsClassAndSourceIndexes() + + + /** + * Verifies that sniffs by default are listening for PHP files only. + * + * @return void + */ + public function testSetsSupportedTokenizersToPHPByDefault() + { + $exclude = 'Fixtures\\TestStandard\\Sniffs\\SupportedTokenizers\\ListensForPHPAndCSSAndJSSniff'; + $expected = ['PHP' => 'PHP']; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'tokenizers', + $details, + sprintf('"tokenizers" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + $details['tokenizers'], + sprintf('Unexpected value for "tokenizers" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsSupportedTokenizersToPHPByDefault() + + + /** + * Test that if a sniff has the $supportedTokenizers property set, the tokenizers listed there + * will be registered in the listeners array. + * + * @param int $token The token constant for which the sniff should be registered. + * + * @dataProvider dataSetsSupportedTokenizersWhenProvidedBySniff + * + * @return void + */ + public function testSetsSupportedTokenizersWhenProvidedBySniff($token) + { + $sniffClass = 'Fixtures\\TestStandard\\Sniffs\\SupportedTokenizers\\ListensForPHPAndCSSAndJSSniff'; + $expected = [ + 'PHP' => 'PHP', + 'JS' => 'JS', + 'CSS' => 'CSS', + ]; + + $this->assertArrayHasKey( + $token, + self::$ruleset->tokenListeners, + sprintf('The token constant %s is not registered to the listeners array', Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $sniffClass, + self::$ruleset->tokenListeners[$token], + sprintf('The sniff class %s is not registered for token %s', $sniffClass, Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + 'tokenizers', + self::$ruleset->tokenListeners[$token][$sniffClass], + sprintf('"tokenizers" key missing for sniff class %s for token %s', $sniffClass, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + self::$ruleset->tokenListeners[$token][$sniffClass]['tokenizers'], + sprintf('Unexpected value for "tokenizers" key for sniff class %s for token %s', $sniffClass, Tokens::tokenName($token)) + ); + + }//end testSetsSupportedTokenizersWhenProvidedBySniff() + + + /** + * Data provider. + * + * @see testSetsSupportedTokenizersWhenProvidedBySniff() + * + * @return array> + */ + public static function dataSetsSupportedTokenizersWhenProvidedBySniff() + { + return [ + 'T_OPEN_TAG' => [T_OPEN_TAG], + 'T_OPEN_TAG_WITH_ECHO' => [T_OPEN_TAG_WITH_ECHO], + ]; + + }//end dataSetsSupportedTokenizersWhenProvidedBySniff() + + + /** + * Verifies that by default no explicit include patterns are registered for sniffs. + * + * @return void + */ + public function testSetsIncludePatternsToEmptyArrayByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'include', + $details, + sprintf('"include" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + [], + $details['include'], + sprintf('Unexpected value for "include" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsIncludePatternsToEmptyArrayByDefault() + + + /** + * Verifies that by default no explicit ignore patterns are registered for sniffs. + * + * @return void + */ + public function testSetsIgnorePatternsToEmptyArrayByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'ignore', + $details, + sprintf('"ignore" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + [], + $details['ignore'], + sprintf('Unexpected value for "ignore" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsIgnorePatternsToEmptyArrayByDefault() + + + /** + * Tests that if there are <[include|exclude]-pattern> directives set on a sniff, these are set for the relevant listeners. + * + * Includes verification that the transformation of "regex"-like patterns is handled correctly. + * + * @param int|string $token A token constant on which the sniff should be registered. + * @param string $sniffClass The FQN for the sniff class on which the patterns should be registered. + * @param string $patternType The type of patterns expected to be registered for the sniff. + * + * @dataProvider dataSetsIncludeAndIgnorePatterns + * + * @return void + */ + public function testSetsIncludeAndIgnorePatterns($token, $sniffClass, $patternType) + { + $expected = [ + '/no-transformation/', + '/simple.*transformation/.*', + '/escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css', + '/pat?tern(is|regex)\\.php$', + ]; + + $this->assertArrayHasKey( + $token, + self::$ruleset->tokenListeners, + sprintf('The token constant %s is not registered to the listeners array', Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $sniffClass, + self::$ruleset->tokenListeners[$token], + sprintf('The sniff class %s is not registered for token %s', $sniffClass, Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $patternType, + self::$ruleset->tokenListeners[$token][$sniffClass], + sprintf('"%s" key missing for sniff class %s for token %s', $patternType, $sniffClass, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + self::$ruleset->tokenListeners[$token][$sniffClass][$patternType], + sprintf('Unexpected value for "%s" key for sniff class %s for token %s', $patternType, $sniffClass, Tokens::tokenName($token)) + ); + + }//end testSetsIncludeAndIgnorePatterns() + + + /** + * Data provider. + * + * @see testSetsIncludeAndIgnorePatterns() + * + * @return array> + */ + public static function dataSetsIncludeAndIgnorePatterns() + { + return [ + 'Sniff with s in the ruleset - first token' => [ + 'token' => T_STRING, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'patternType' => 'include', + ], + 'Sniff with s in the ruleset - second token' => [ + 'token' => T_CONST, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'patternType' => 'include', + ], + 'Sniff with s in the ruleset' => [ + 'token' => T_OPEN_TAG, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'patternType' => 'ignore', + ], + ]; + + }//end dataSetsIncludeAndIgnorePatterns() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.xml new file mode 100644 index 00000000..1b6ed1a4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /no-transformation/ + /simple*transformation/* + /escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css + /pat?tern(is|regex)\.php$ + + + + + /no-transformation/ + /simple*transformation/* + /escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css + /pat?tern(is|regex)\.php$ + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php new file mode 100644 index 00000000..d43958c7 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php @@ -0,0 +1,43 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of invalid type elements. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + */ +final class ProcessRuleInvalidTypeTest extends AbstractRulesetTestCase +{ + + + /** + * Test displaying an error when an invalid type is given. + * + * @return void + */ + public function testInvalidTypeHandling() + { + $standard = __DIR__.'/ProcessRuleInvalidTypeTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $message = 'ERROR: Message type "notice" for "Generic.Files.ByteOrderMark" is invalid; must be "error" or "warning".'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testInvalidTypeHandling() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml new file mode 100644 index 00000000..4883e910 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml @@ -0,0 +1,9 @@ + + + + + + notice + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php new file mode 100644 index 00000000..c6c9e216 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php @@ -0,0 +1,666 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of `phpc(cs|cbf)-only` instructions at rule level. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + * @covers \PHP_CodeSniffer\Ruleset::shouldProcessElement + */ +final class ProcessRuleShouldProcessElementTest extends AbstractRulesetTestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRuleShouldProcessElementTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessSeverityCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'severity'; + + // Verify that the non-selective severity directive IS applied. + $sniffCode = 'Internal.NoCodeFound'; + $this->assertRulesetPropertySame(0, $sniffCode, $key); + + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame(3, $sniffCode, $key); + + // Verify that the CS-only severity directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame(2, $sniffCode, $key); + + // Verify that the CBF-only severity directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessSeverityCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessSeverityCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'severity'; + + // Verify that the non-selective severity directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame(3, $sniffCode, $key); + + // Verify that the CS-only severity directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only severity directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame(4, $sniffCode, $key); + + }//end testShouldProcessSeverityCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessTypeCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'type'; + + // Verify that the non-selective type directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CS-only type directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CBF-only type directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessTypeCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessTypeCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'type'; + + // Verify that the non-selective type directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CS-only type directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only type directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame('error', $sniffCode, $key); + + }//end testShouldProcessTypeCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessMessageCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'message'; + + // Verify that the non-selective message directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('A different warning message', $sniffCode, $key); + + // Verify that the CS-only message directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame('A different warning but only for phpcs', $sniffCode, $key); + + // Verify that the CBF-only message directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessMessageCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessMessageCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'message'; + + // Verify that the non-selective message directive IS applied. + $sniffCode = 'Internal.NoCodeFound'; + $this->assertRulesetPropertySame("We don't to be notified if files don't contain code", $sniffCode, $key); + + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('A different warning message', $sniffCode, $key); + + // Verify that the CS-only message directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only message directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame('A different warning but only for phpcbf', $sniffCode, $key); + + }//end testShouldProcessMessageCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessIncludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $includedKey = './vendor/'; + + // Verify that the non-selective include-pattern directive IS applied. + $sniffCode = 'PSR1.Methods.CamelCapsMethodName'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only include-pattern directive IS applied. + $sniffCode = 'Generic.Files.LineLength'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CBF-only include-pattern directive is NOT applied. + $sniffCode = 'PSR2.Files.ClosingTag'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode was registered"); + + }//end testShouldProcessIncludePatternCsonly() + + + /** + * Verify that in CS mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessIncludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $includedKey = './vendor/'; + + // Verify that the non-selective include-pattern directive IS applied. + $sniffCode = 'PSR1.Methods.CamelCapsMethodName'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only include-pattern directive is NOT applied. + $sniffCode = 'Generic.Files.LineLength'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode was registered"); + + // Verify that the CBF-only include-pattern directive is IS applied. + $sniffCode = 'PSR2.Files.ClosingTag'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + }//end testShouldProcessIncludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessExcludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $excludedKey = './tests/'; + + // Verify that the non-selective exclude-pattern directive IS applied. + $sniffCode = 'PSR1.Classes.ClassDeclaration'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only exclude-pattern directive IS applied. + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CBF-only exclude-pattern directive is NOT applied. + $sniffCode = 'PSR2.Methods.FunctionClosingBrace'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode was registered"); + + }//end testShouldProcessExcludePatternCsonly() + + + /** + * Verify that in CS mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessExcludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $excludedKey = './tests/'; + + // Verify that the non-selective exclude-pattern directive IS applied. + $sniffCode = 'PSR1.Classes.ClassDeclaration'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only exclude-pattern directive is NOT applied. + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode was registered"); + + // Verify that the CBF-only exclude-pattern directive is IS applied. + $sniffCode = 'PSR2.Methods.FunctionClosingBrace'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + }//end testShouldProcessExcludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessPropertiesCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $csSniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff'; + $cbfSniffClass = 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff'; + + $propertyName = 'indent'; + $propertyDefault = 4; + $propertyChanged = '2'; + + // Verify that the CS-only property directive IS applied. + $this->assertArrayHasKey($csSniffClass, self::$ruleset->sniffs, "Sniff $csSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$csSniffClass]); + + $actualValue = self::$ruleset->sniffs[$csSniffClass]->$propertyName; + $this->assertSame($propertyChanged, $actualValue, 'cs-only property change directive not applied'); + + // Verify that the CBF-only property directive is NOT applied. + $this->assertArrayHasKey($cbfSniffClass, self::$ruleset->sniffs, "Sniff $cbfSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$cbfSniffClass]); + + $actualValue = self::$ruleset->sniffs[$cbfSniffClass]->$propertyName; + $this->assertSame($propertyDefault, $actualValue, 'cbf-only property change directive was applied'); + + }//end testShouldProcessPropertiesCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessPropertiesCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $csSniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff'; + $cbfSniffClass = 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff'; + + $propertyName = 'indent'; + $propertyDefault = 4; + $propertyChanged = '2'; + + // Verify that the CS-only property directive is NOT applied. + $this->assertArrayHasKey($csSniffClass, self::$ruleset->sniffs, "Sniff $csSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$csSniffClass]); + + $actualValue = self::$ruleset->sniffs[$csSniffClass]->$propertyName; + $this->assertSame($propertyDefault, $actualValue, 'cs-only property change directive was applied'); + + // Verify that the CBF-only property directive IS applied. + $this->assertArrayHasKey($cbfSniffClass, self::$ruleset->sniffs, "Sniff $cbfSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$cbfSniffClass]); + + $actualValue = self::$ruleset->sniffs[$cbfSniffClass]->$propertyName; + $this->assertSame($propertyChanged, $actualValue, 'cbf-only property change directive not applied'); + + }//end testShouldProcessPropertiesCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessPropertyCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify that the non-selective property directive IS applied. + $propertyName = 'exact'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'Non-selective property change directive not applied'); + + // Verify that the CS-only property directive IS applied. + $propertyName = 'indent'; + $expected = '2'; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'cs-only property change directive not applied'); + + // Verify that the CBF-only property directive is NOT applied. + $propertyName = 'tabIndent'; + $expectedDefault = false; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expectedDefault, $sniffObject->$propertyName, 'cbf-only property change directive was applied'); + + }//end testShouldProcessPropertyCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessPropertyCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify that the non-selective property directive IS applied. + $propertyName = 'exact'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'Non-selective property change directive not applied'); + + // Verify that the CS-only property directive is NOT applied. + $propertyName = 'indent'; + $expectedDefault = 4; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expectedDefault, $sniffObject->$propertyName, 'cs-only property change directive was applied'); + + // Verify that the CBF-only property directive IS applied. + $propertyName = 'tabIndent'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'cbf-only property change directive not applied'); + + }//end testShouldProcessPropertyCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessElementCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + // Non-selective element directive. + 'T_COMMENT', + // Phpcs-only element directive. + 'T_CLASS', + // Non-selective element directive via `extend`. + 'T_BACKTICK', + // Phpcs-only element directive via `extend`. + 'T_INTERFACE', + ]; + + $this->verifyShouldProcessElement($expected); + + }//end testShouldProcessElementCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessElementCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + // Non-selective element directive. + 'T_COMMENT', + // Phpcbf-only element directive. + 'T_ENUM', + // Non-selective element directive via `extend`. + 'T_BACKTICK', + // Phpcbf-only element directive via `extend`. + 'T_TRAIT', + ]; + + $this->verifyShouldProcessElement($expected); + + }//end testShouldProcessElementCbfonly() + + + /** + * Verify that directives are set correctly. + * + * @param array $expected Expected sniff property value. + * + * @return void + */ + private function verifyShouldProcessElement($expected) + { + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + // Verify the target property exists. + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + $propertyName = 'ignoreIndentationTokens'; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + + // Verify the value. + $actualValue = $sniffObject->$propertyName; + $this->assertSame($expected, $actualValue, 'Selective element directives not applied correctly'); + + }//end verifyShouldProcessElement() + + + /** + * Custom assertion to verify that a Ruleset `$ruleset` property has a certain directive set for a certain sniff code. + * + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertHasRulesetDirective($sniffCode, $key) + { + $this->assertArrayHasKey($sniffCode, self::$ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array(self::$ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, self::$ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + + }//end assertHasRulesetDirective() + + + /** + * Custom assertion to verify that a Ruleset `$ruleset` property does NOT have a certain directive set for a certain sniff code. + * + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertNotHasRulesetDirective($sniffCode, $key) + { + if (isset(self::$ruleset->ruleset[$sniffCode]) === true + && is_array(self::$ruleset->ruleset[$sniffCode]) === true + && isset(self::$ruleset->ruleset[$sniffCode][$key]) === true + ) { + $this->fail("Directive $key is registered for sniff $sniffCode"); + } + + }//end assertNotHasRulesetDirective() + + + /** + * Custom assertion to verify that the value of a certain directive for a certain sniff code on the ruleset is correct. + * + * @param mixed $expected Expected value. + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertRulesetPropertySame($expected, $sniffCode, $key) + { + $this->assertHasRulesetDirective($sniffCode, $key); + + $actual = self::$ruleset->ruleset[$sniffCode][$key]; + $this->assertSame($expected, $actual, "Value for $key on sniff $sniffCode does not meet expectations"); + + }//end assertRulesetPropertySame() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml new file mode 100644 index 00000000..a8a6f4d7 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml @@ -0,0 +1,105 @@ + + + + + + 0 + We don't to be notified if files don't contain code + + + + 3 + warning + A different warning message + + + + ./vendor/ + + + + ./tests/ + + + + + + + 2 + warning + A different warning but only for phpcs + + + + ./vendor/ + + + + ./tests/ + + + + + + + + + + + 4 + error + A different warning but only for phpcbf + + + + ./vendor/ + + + + ./tests/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml new file mode 100644 index 00000000..5290782d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml new file mode 100644 index 00000000..6df4c63f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml @@ -0,0 +1,8 @@ + + + + ./tests/Core/Ruleset/Fixtures/ThisFileDoesNotExist.php + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php new file mode 100644 index 00000000..1f6e289e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php @@ -0,0 +1,164 @@ + instructions. + * + * @author Juliette Reinders Folmer + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of instructions. + * + * Note: these tests need to run in separate processes as otherwise we cannot + * reliably determine whether or not the correct files were loaded as the + * underlying code uses `include_once`. + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetAutoloadTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessAutoloadCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $originallyIncludes = get_included_files(); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + $finalIncludes = get_included_files(); + $diff = array_diff($finalIncludes, $originallyIncludes); + + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.1.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.2.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.2.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.3.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.4.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcsOnly.php autoload file was not loaded' + ); + $this->assertNotContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcbfOnly.php autoload file was loaded, while it shouldn\'t have been' + ); + + }//end testShouldProcessAutoloadCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessAutoloadCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $originallyIncludes = get_included_files(); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + $finalIncludes = get_included_files(); + $diff = array_diff($finalIncludes, $originallyIncludes); + + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.1.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.2.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.2.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.3.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.4.php autoload file was not loaded' + ); + $this->assertNotContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcsOnly.php autoload file was loaded, while it shouldn\'t have been' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcbfOnly.php autoload file was not loaded' + ); + + }//end testShouldProcessAutoloadCbfonly() + + + /** + * Test an exception is thrown when the directive points to a file which doesn't exist. + * + * @return void + */ + public function testFileNotFoundException() + { + $exceptionMsg = 'ERROR: The specified autoload file "./tests/Core/Ruleset/Fixtures/ThisFileDoesNotExist.php" does not exist'; + $this->expectRuntimeExceptionMessage($exceptionMsg); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadFileNotFoundTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testFileNotFoundException() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml new file mode 100644 index 00000000..f886288e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml @@ -0,0 +1,37 @@ + + + + . + + + + ./Fixtures/ProcessRulesetAutoloadLoadAlways.1.php + Fixtures/ProcessRulesetAutoloadLoadAlways.2.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php + tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetEmptyFileTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetEmptyFileTest.xml new file mode 100644 index 00000000..e69de29b diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml new file mode 100644 index 00000000..211b5683 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml new file mode 100644 index 00000000..37aeef6b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml @@ -0,0 +1,2 @@ + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php new file mode 100644 index 00000000..2798c2fc --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php @@ -0,0 +1,96 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of broken ruleset files. + * + * Note: these tests need to run in separate processes as otherwise they run into + * some weirdness with the libxml_get_errors()/libxml_clear_errors() functions + * (duplicate error messages). + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * + * @group Windows + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetBrokenRulesetTest extends AbstractRulesetTestCase +{ + + + /** + * Test displaying an informative error message when an empty XML ruleset file is encountered. + * + * @return void + */ + public function testBrokenRulesetEmptyFile() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetEmptyFileTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^ERROR: Ruleset \S+ProcessRulesetBrokenRulesetEmptyFileTest\.xml is not valid\R'; + $regex .= '(- On line 1, column 1: Document is empty\R)?$`'; + + $this->expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetEmptyFile() + + + /** + * Test displaying an informative error message for a broken XML ruleset with a single XML error. + * + * @return void + */ + public function testBrokenRulesetSingleError() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetSingleErrorTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^ERROR: Ruleset \S+ProcessRulesetBrokenRulesetSingleErrorTest\.xml is not valid\R'; + $regex .= '- On line 3, column 1: (Premature end of data in tag ruleset line 2|EndTag: \'expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetSingleError() + + + /** + * Test displaying an informative error message for a broken XML ruleset with multiple XML errors. + * + * @return void + */ + public function testBrokenRulesetMultiError() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetMultiErrorTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^ERROR: Ruleset \S+ProcessRulesetBrokenRulesetMultiErrorTest\.xml is not valid\R'; + $regex .= '- On line 8, column 12: Opening and ending tag mismatch: property line 7 and rule\R'; + $regex .= '- On line 10, column 11: Opening and ending tag mismatch: properties line [57] and ruleset\R'; + $regex .= '(- On line 11, column 1: (Premature end of data in tag rule(set)? line [24]|EndTag: \'expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetMultiError() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml new file mode 100644 index 00000000..5aa4aede --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml new file mode 100644 index 00000000..59874358 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetMiscTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetMiscTest.xml new file mode 100644 index 00000000..7adef228 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetMiscTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php new file mode 100644 index 00000000..59fce1b1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php @@ -0,0 +1,391 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Config; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test handling of `phpc(cs|cbf)-only` instructions at ruleset level. + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + * @covers \PHP_CodeSniffer\Ruleset::shouldProcessElement + */ +final class ProcessRulesetShouldProcessElementTest extends TestCase +{ + + /** + * Cache to store the original ini values for ini settings being changed in these tests. + * + * @var array + */ + private static $originalIniValues = [ + 'bcmath.scale' => null, + 'docref_root' => null, + 'user_agent' => null, + ]; + + /** + * The Config object. + * + * @var \PHP_CodeSniffer\Tests\ConfigDouble + */ + private static $config; + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Store the original ini values to allow for restoring them after the tests. + * + * @beforeClass + * + * @return void + */ + public static function saveOriginalIniValues() + { + foreach (self::$originalIniValues as $name => $null) { + $value = ini_get($name); + if ($value !== false) { + self::$originalIniValues[$name] = $value; + } + } + + }//end saveOriginalIniValues() + + + /** + * Initialize the config and ruleset objects for this test only once (but do allow recording code coverage). + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetShouldProcessElementTest.xml'; + self::$config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset(self::$config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Destroy the Config object and restore the ini values after the tests. + * + * @afterClass + * + * @return void + */ + public static function restoreOriginalValues() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when this object is destroyed, but we can't definitively rely on that). + if (isset(self::$config) === true) { + self::$config->__destruct(); + } + + foreach (self::$originalIniValues as $name => $value) { + if ($value === null) { + continue; + } + + ini_set($name, $value); + } + + }//end restoreOriginalValues() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessConfigCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertSame('true', Config::getConfigData('neither'), 'Non-selective config directive was not applied.'); + $this->assertSame('true', Config::getConfigData('csOnly'), 'CS-only config directive was not applied.'); + $this->assertSame(null, Config::getConfigData('cbfOnly'), 'CBF-only config directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessConfigCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessConfigCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertSame('true', Config::getConfigData('neither'), 'Non-selective config directive was not applied.'); + $this->assertSame(null, Config::getConfigData('csOnly'), 'CS-only config directive was applied, while it shouldn\'t have been.'); + $this->assertSame('true', Config::getConfigData('cbfOnly'), 'CBF-only config directive was not applied.'); + + }//end testShouldProcessConfigCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessArgCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expectedExtensions = [ + 'php' => 'PHP', + 'phpt' => 'PHP', + ]; + $expectedReports = ['full' => null]; + + $this->assertSame($expectedExtensions, self::$config->extensions, 'Non-selective arg directive was not applied.'); + $this->assertTrue(self::$config->showProgress, 'Non-selective short arg directive was not applied [1].'); + $this->assertTrue(self::$config->showSources, 'Non-selective short arg directive was not applied [2].'); + $this->assertTrue(self::$config->colors, 'CS-only arg directive was not applied.'); + $this->assertSame($expectedReports, self::$config->reports, 'CBF-only arg directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessArgCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessArgCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expectedExtensions = [ + 'php' => 'PHP', + 'phpt' => 'PHP', + ]; + $expectedReports = ['summary' => null]; + + $this->assertSame($expectedExtensions, self::$config->extensions, 'Non-selective arg directive was not applied.'); + $this->assertTrue(self::$config->showProgress, 'Non-selective short arg directive was not applied [1].'); + $this->assertTrue(self::$config->showSources, 'Non-selective short arg directive was not applied [2].'); + $this->assertFalse(self::$config->colors, 'CS-only arg directive was applied, while it shouldn\'t have been.'); + $this->assertSame($expectedReports, self::$config->reports, 'CBF-only arg directive was not applied.'); + + }//end testShouldProcessArgCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @requires extension bcmath + * + * @return void + */ + public function testShouldProcessIniCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertSame('2', ini_get('bcmath.scale'), 'Non-selective ini directive was not applied.'); + $this->assertSame('path/to/docs/', ini_get('docref_root'), 'CS-only ini directive was not applied.'); + $this->assertSame('', ini_get('user_agent'), 'CBF-only ini directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessIniCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * @requires extension bcmath + * + * @return void + */ + public function testShouldProcessIniCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertSame('2', ini_get('bcmath.scale'), 'Non-selective ini directive was not applied.'); + $this->assertSame('', ini_get('docref_root'), 'CS-only ini directive was applied, while it shouldn\'t have been..'); + $this->assertSame('Never mind', ini_get('user_agent'), 'CBF-only ini directive was not applied.'); + + }//end testShouldProcessIniCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessExcludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + './tests/' => 'absolute', + './vendor/' => 'absolute', + ]; + + $this->assertSame($expected, self::$ruleset->ignorePatterns); + + }//end testShouldProcessExcludePatternCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessExcludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + './tests/' => 'absolute', + './node-modules/' => 'absolute', + ]; + + $this->assertSame($expected, self::$ruleset->ignorePatterns); + + }//end testShouldProcessExcludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessRuleCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertArrayHasKey('PEAR.Formatting.MultiLineAssignment', self::$ruleset->sniffCodes); + $this->assertArrayHasKey('Generic.Arrays.ArrayIndent', self::$ruleset->sniffCodes); + $this->assertArrayNotHasKey('PSR2.Classes.ClassDeclaration', self::$ruleset->sniffCodes); + + }//end testShouldProcessRuleCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessRuleCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertArrayHasKey('PEAR.Formatting.MultiLineAssignment', self::$ruleset->sniffCodes); + $this->assertArrayNotHasKey('Generic.Arrays.ArrayIndent', self::$ruleset->sniffCodes); + $this->assertArrayHasKey('PSR2.Classes.ClassDeclaration', self::$ruleset->sniffCodes); + + }//end testShouldProcessRuleCbfonly() + + + /** + * Verify that in CS mode, phpcs-only in directives are respected and phpcbf-only in + * directives are ignored. + * + * @return void + */ + public function testShouldProcessRuleExcludeCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + 'PEAR.Formatting.MultiLineAssignment.Indent' => [ + 'severity' => 0, + ], + ]; + + $this->assertSame($expected, self::$ruleset->ruleset); + + }//end testShouldProcessRuleExcludeCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only in directives are respected and phpcs-only in + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessRuleExcludeCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + 'PEAR.Formatting.MultiLineAssignment.EqualSignLine' => [ + 'severity' => 0, + ], + ]; + + $this->assertSame($expected, self::$ruleset->ruleset); + + }//end testShouldProcessRuleExcludeCbfonly() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml new file mode 100644 index 00000000..2a256672 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml @@ -0,0 +1,54 @@ + + + + . + + + + + + + + ./tests/ + + + + + + + + + ./vendor/ + + + + + + + + + + + + + ./node-modules/ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetTest.php new file mode 100644 index 00000000..d37c0310 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetTest.php @@ -0,0 +1,266 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test various aspects of the Ruleset::processRuleset() method not covered via other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetTest extends TestCase +{ + + + /** + * Verify that a registered standard which doesn't have a "Sniffs" directory, but does have a file + * called "Sniffs" doesn't result in any errors being thrown. + * + * @return void + */ + public function testSniffsFileNotDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetInvalidNoSniffsDirTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\BacktickOperatorSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testSniffsFileNotDirectory() + + + /** + * Verify that all sniffs in a registered standard included in a ruleset automatically get added. + * + * @return void + */ + public function testAutoExpandSniffsDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoExpandSniffsDirectoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $std = 'TestStandard'; + $sniffDir = 'Fixtures\TestStandard\Sniffs'; + $expected = [ + "$std.Deprecated.WithLongReplacement" => "$sniffDir\Deprecated\WithLongReplacementSniff", + "$std.Deprecated.WithReplacement" => "$sniffDir\Deprecated\WithReplacementSniff", + "$std.Deprecated.WithReplacementContainingLinuxNewlines" => "$sniffDir\Deprecated\WithReplacementContainingLinuxNewlinesSniff", + "$std.Deprecated.WithReplacementContainingNewlines" => "$sniffDir\Deprecated\WithReplacementContainingNewlinesSniff", + "$std.Deprecated.WithoutReplacement" => "$sniffDir\Deprecated\WithoutReplacementSniff", + "$std.DeprecatedInvalid.EmptyDeprecationVersion" => "$sniffDir\DeprecatedInvalid\EmptyDeprecationVersionSniff", + "$std.DeprecatedInvalid.EmptyRemovalVersion" => "$sniffDir\DeprecatedInvalid\EmptyRemovalVersionSniff", + "$std.DeprecatedInvalid.InvalidDeprecationMessage" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationMessageSniff", + "$std.DeprecatedInvalid.InvalidDeprecationVersion" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationVersionSniff", + "$std.DeprecatedInvalid.InvalidRemovalVersion" => "$sniffDir\DeprecatedInvalid\InvalidRemovalVersionSniff", + "$std.MissingInterface.ValidImplements" => "$sniffDir\MissingInterface\ValidImplementsSniff", + "$std.MissingInterface.ValidImplementsViaAbstract" => "$sniffDir\MissingInterface\ValidImplementsViaAbstractSniff", + "$std.SetProperty.AllowedAsDeclared" => "$sniffDir\SetProperty\AllowedAsDeclaredSniff", + "$std.SetProperty.AllowedViaMagicMethod" => "$sniffDir\SetProperty\AllowedViaMagicMethodSniff", + "$std.SetProperty.AllowedViaStdClass" => "$sniffDir\SetProperty\AllowedViaStdClassSniff", + "$std.SetProperty.NotAllowedViaAttribute" => "$sniffDir\SetProperty\NotAllowedViaAttributeSniff", + "$std.SetProperty.PropertyTypeHandling" => "$sniffDir\SetProperty\PropertyTypeHandlingSniff", + "$std.ValidSniffs.RegisterEmptyArray" => "$sniffDir\ValidSniffs\RegisterEmptyArraySniff", + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expected, $actual); + + }//end testAutoExpandSniffsDirectory() + + + /** + * Verify handling of exclusions of groups of sniffs after inclusion via an even larger "group". + * + * @return void + */ + public function testExcludeSniffGroup() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetExcludeSniffGroupTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = [ + 'PSR1.Classes.ClassDeclaration' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', + 'PSR1.Methods.CamelCapsMethodName' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Methods\CamelCapsMethodNameSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expected, $actual); + + }//end testExcludeSniffGroup() + + + /* + * No test for without "name" as there is nothing we can assert to verify it's being ignored. + */ + + + /** + * Test that an `` directive without a "value" attribute will be set to the ini equivalent of `true`. + * + * @return void + */ + public function testIniWithoutValue() + { + $originalValue = ini_get('user_agent'); + + // Set up the ruleset. + $this->getMiscRuleset(); + + $actualValue = ini_get('user_agent'); + // Reset the ini to its original value before the assertion to ensure it's never left in an incorrect state. + if ($originalValue !== false) { + ini_set('user_agent', $originalValue); + } + + $this->assertSame('1', $actualValue); + + }//end testIniWithoutValue() + + + /** + * Verify that inclusion of a single error code: + * - Includes the sniff, but sets "severity" for the sniff to 0; + * - Sets "severity" for the specific error code included to 5.; + * + * @return void + */ + public function testIncludeSingleErrorCode() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $key = 'severity'; + + $sniffCode = 'Generic.PHP.RequireStrictTypes'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'Generic.PHP.RequireStrictTypes.MissingDeclaration'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + }//end testIncludeSingleErrorCode() + + + /** + * Verify that if all error codes, save one, from a sniff were previously excluded, an include for an additional + * error code from that same sniff will be respected. + * + * @return void + */ + public function testErrorCodeIncludeAfterExclude() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $key = 'severity'; + + $sniffCode = 'PEAR.Files.IncludingFile'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'PEAR.Files.IncludingFile.BracketsNotRequired'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'PEAR.Files.IncludingFile.UseRequire'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + }//end testErrorCodeIncludeAfterExclude() + + + /** + * Verify that a element without a "ref" is completely ignored. + * + * @return void + */ + public function testRuleWithoutRefIsIgnored() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode registered"); + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + }//end testRuleWithoutRefIsIgnored() + + + /** + * Verify that no "ruleset adjustments" are registered via an `` without a "name". + * + * @return void + */ + public function testRuleExcludeWithoutNameIsIgnored() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $sniffCode = 'Generic.PHP.BacktickOperator'; + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode not registered"); + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + $sniffCode = 'Generic.PHP.BacktickOperator.Found'; + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + }//end testRuleExcludeWithoutNameIsIgnored() + + + /** + * Test Helper. + * + * @return \PHP_CodeSniffer\Ruleset + */ + private function getMiscRuleset() + { + static $ruleset; + + if (isset($ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetMiscTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + } + + return $ruleset; + + }//end getMiscRuleset() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml new file mode 100644 index 00000000..8f276f81 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.php new file mode 100644 index 00000000..1db15aa5 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.php @@ -0,0 +1,333 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Files\LocalFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the handling of property value types for properties set via the ruleset and inline. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + * @covers \PHP_CodeSniffer\Ruleset::setSniffProperty + */ +final class PropertyTypeHandlingTest extends TestCase +{ + + /** + * Sniff code for the sniff used in these tests. + * + * @var string + */ + const SNIFF_CODE = 'TestStandard.SetProperty.PropertyTypeHandling'; + + /** + * Class name of the sniff used in these tests. + * + * @var string + */ + const SNIFF_CLASS = 'Fixtures\\TestStandard\\Sniffs\\SetProperty\\PropertyTypeHandlingSniff'; + + + /** + * Verify a deprecation notice is shown when an array property is set from the ruleset using a comma-separated string. + * + * Support for this format was (soft) deprecated in PHPCS 3.3.0. + * + * @return void + */ + public function testUsingOldSchoolArrayFormatShowsDeprecationNotice() + { + $regex = '`^('; + $regex .= 'DEPRECATED: Passing an array of values to a property using a comma-separated string\R'; + $regex .= 'was deprecated in PHP_CodeSniffer 3\.3\.0\. Support will be removed in PHPCS 4\.0\.0\.\R'; + $regex .= 'The deprecated syntax was used for property "expectsOldSchool(?:EmptyArray|ArrayWith(?:Extended|Only)?(?:KeysAnd)?Values)"\R'; + $regex .= 'for sniff "'; + $regex .= '(?:\./tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/PropertyTypeHandlingSniff\.php|TestStandard\.SetProperty\.PropertyTypeHandling)'; + $regex .= '"\.\R'; + $regex .= 'Pass array values via nodes instead\.\R'; + $regex .= '){14}\R$`'; + + $this->expectOutputRegex($regex); + + // Set up the ruleset. + $standard = __DIR__.'/PropertyTypeHandlingTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testUsingOldSchoolArrayFormatShowsDeprecationNotice() + + + /** + * Test the value type handling for properties set via a ruleset. + * + * @param string $propertyName Property name. + * @param mixed $expected Expected property value. + * + * @dataProvider dataTypeHandling + * @dataProvider dataArrayPropertyExtending + * + * @return void + */ + public function testTypeHandlingWhenSetViaRuleset($propertyName, $expected) + { + $sniffObject = $this->getSniffObjectForRuleset(); + + $this->assertSame($expected, $sniffObject->$propertyName); + + }//end testTypeHandlingWhenSetViaRuleset() + + + /** + * Test the value type handling for properties set inline in a test case file. + * + * @param string $propertyName Property name. + * @param mixed $expected Expected property value. + * + * @dataProvider dataTypeHandling + * + * @return void + */ + public function testTypeHandlingWhenSetInline($propertyName, $expected) + { + $sniffObject = $this->getSniffObjectAfterProcessingFile(); + + $this->assertSame($expected, $sniffObject->$propertyName); + + }//end testTypeHandlingWhenSetInline() + + + /** + * Data provider. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * @see self::testTypeHandlingWhenSetInline() + * + * @return array> + */ + public static function dataTypeHandling() + { + $expectedArrayOnlyValues = [ + 'string', + '10', + '1.5', + 'null', + 'true', + 'false', + ]; + $expectedArrayKeysAndValues = [ + 'string' => 'string', + 10 => '10', + 'float' => '1.5', + 'null' => 'null', + 'true' => 'true', + 'false' => 'false', + ]; + + return [ + 'String value (default)' => [ + 'propertyName' => 'expectsString', + 'expected' => 'arbitraryvalue', + ], + 'String value with whitespace gets trimmed' => [ + 'propertyName' => 'expectsTrimmedString', + 'expected' => 'some value', + ], + 'String with whitespace only value becomes null' => [ + 'propertyName' => 'emptyStringBecomesNull', + 'expected' => null, + ], + 'Integer value gets set as string' => [ + 'propertyName' => 'expectsIntButAcceptsString', + 'expected' => '12345', + ], + 'Float value gets set as string' => [ + 'propertyName' => 'expectsFloatButAcceptsString', + 'expected' => '12.345', + ], + 'Null value gets set as string' => [ + 'propertyName' => 'expectsNull', + 'expected' => 'null', + ], + 'Null (uppercase) value gets set as string' => [ + 'propertyName' => 'expectsNullCase', + 'expected' => 'NULL', + ], + 'True value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanTrue', + 'expected' => true, + ], + 'True (mixed case) value gets set as string' => [ + 'propertyName' => 'expectsBooleanTrueCase', + 'expected' => 'True', + ], + 'True (with spaces) value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanTrueTrimmed', + 'expected' => true, + ], + 'False value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanFalse', + 'expected' => false, + ], + 'False (mixed case) value gets set as string' => [ + 'propertyName' => 'expectsBooleanFalseCase', + 'expected' => 'fALSe', + ], + 'False (with spaces) value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanFalseTrimmed', + 'expected' => false, + ], + 'Array with only values (new style)' => [ + 'propertyName' => 'expectsArrayWithOnlyValues', + 'expected' => $expectedArrayOnlyValues, + ], + 'Array with keys and values (new style)' => [ + 'propertyName' => 'expectsArrayWithKeysAndValues', + 'expected' => $expectedArrayKeysAndValues, + ], + 'Empty array (new style)' => [ + 'propertyName' => 'expectsEmptyArray', + 'expected' => [], + ], + 'Array with only values (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithOnlyValues', + 'expected' => $expectedArrayOnlyValues, + ], + 'Array with keys and values (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithKeysAndValues', + 'expected' => $expectedArrayKeysAndValues, + ], + 'Empty array (old style)' => [ + 'propertyName' => 'expectsOldSchoolEmptyArray', + 'expected' => [], + ], + ]; + + }//end dataTypeHandling() + + + /** + * Data provider. + * + * Array property extending is a feature which is only supported from a ruleset, not for inline property setting. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * + * @return array> + */ + public static function dataArrayPropertyExtending() + { + $expectedArrayOnlyValuesExtended = [ + 'string', + '15', + 'another string', + ]; + $expectedArrayKeysAndValuesExtended = [ + 10 => '10', + 'string' => 'string', + 15 => '15', + 'another string' => 'another string', + ]; + + return [ + 'Array with only values extended (new style)' => [ + 'propertyName' => 'expectsArrayWithExtendedValues', + 'expected' => $expectedArrayOnlyValuesExtended, + ], + 'Array with keys and values extended (new style)' => [ + 'propertyName' => 'expectsArrayWithExtendedKeysAndValues', + 'expected' => $expectedArrayKeysAndValuesExtended, + ], + 'Array with only values extended (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithExtendedValues', + 'expected' => $expectedArrayOnlyValuesExtended, + ], + 'Array with keys and values extended (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithExtendedKeysAndValues', + 'expected' => $expectedArrayKeysAndValuesExtended, + ], + ]; + + }//end dataArrayPropertyExtending() + + + /** + * Test Helper. + * + * Note: the deprecations for using comma-separated string to pass an array, are silenced in this helper + * as that's not what's being tested here. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * + * @return \PHP_CodeSniffer\Sniffs\Sniff + */ + private function getSniffObjectForRuleset() + { + static $sniffObject; + + if (isset($sniffObject) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PropertyTypeHandlingTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '-q']); + $ruleset = new Ruleset($config); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey(self::SNIFF_CODE, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame(self::SNIFF_CLASS, $ruleset->sniffCodes[self::SNIFF_CODE], 'Target sniff not registered with the correct class'); + $this->assertArrayHasKey(self::SNIFF_CLASS, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[self::SNIFF_CLASS]; + } + + return $sniffObject; + + }//end getSniffObjectForRuleset() + + + /** + * Test Helper + * + * @see self::testTypeHandlingWhenSetInline() + * + * @return \PHP_CodeSniffer\Sniffs\Sniff + */ + private function getSniffObjectAfterProcessingFile() + { + static $sniffObject; + + if (isset($sniffObject) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PropertyTypeHandlingInlineTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey(self::SNIFF_CODE, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame(self::SNIFF_CLASS, $ruleset->sniffCodes[self::SNIFF_CODE], 'Target sniff not registered with the correct class'); + $this->assertArrayHasKey(self::SNIFF_CLASS, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[self::SNIFF_CLASS]; + + // Process the file with inline phpcs:set annotations. + $testFile = realpath(__DIR__.'/Fixtures/PropertyTypeHandlingInline.inc'); + $this->assertNotFalse($testFile); + + $phpcsFile = new LocalFile($testFile, $ruleset, $config); + $phpcsFile->process(); + } + + return $sniffObject; + + }//end getSniffObjectAfterProcessingFile() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.xml new file mode 100644 index 00000000..2e89a37b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceInvalidTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceInvalidTest.xml new file mode 100644 index 00000000..d3886c47 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceInvalidTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceTest.php new file mode 100644 index 00000000..89c82c02 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceTest.php @@ -0,0 +1,65 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Tests deprecation of support for sniffs not implementing the PHPCS `Sniff` interface. + * + * @covers \PHP_CodeSniffer\Ruleset::registerSniffs + */ +final class RegisterSniffsMissingInterfaceTest extends TestCase +{ + + + /** + * Test that no deprecation is shown when sniffs implement the `PHP_CodeSniffer\Sniffs\Sniff` interface. + * + * @return void + */ + public function testNoNoticesForSniffsImplementingInterface() + { + // Set up the ruleset. + $standard = __DIR__.'/RegisterSniffsMissingInterfaceValidTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $this->expectOutputString(''); + + new Ruleset($config); + + }//end testNoNoticesForSniffsImplementingInterface() + + + /** + * Test that a deprecation notice is shown if a sniff doesn't implement the Sniff interface. + * + * @return void + */ + public function testDeprecationNoticeWhenSniffDoesntImplementInterface() + { + // Set up the ruleset. + $standard = __DIR__.'/RegisterSniffsMissingInterfaceInvalidTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $expected = 'DEPRECATED: All sniffs must implement the PHP_CodeSniffer\\Sniffs\\Sniff interface.'.PHP_EOL; + $expected .= 'Interface not implemented for sniff Fixtures\\TestStandard\\Sniffs\\MissingInterface\\InvalidImplementsWithoutImplementSniff.'.PHP_EOL; + $expected .= 'Contact the sniff author to fix the sniff.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($expected); + + new Ruleset($config); + + }//end testDeprecationNoticeWhenSniffDoesntImplementInterface() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceValidTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceValidTest.xml new file mode 100644 index 00000000..ed5220ce --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceValidTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml new file mode 100644 index 00000000..9f4c78d7 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml new file mode 100644 index 00000000..c6f4d756 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml new file mode 100644 index 00000000..1077bef5 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffTest.php new file mode 100644 index 00000000..1efe5cdb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffTest.php @@ -0,0 +1,80 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Tests that invalid sniffs will be rejected with an informative error message. + * + * @covers \PHP_CodeSniffer\Ruleset::registerSniffs + */ +final class RegisterSniffsRejectsInvalidSniffTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that an error is thrown if an invalid sniff class is loaded. + * + * @param string $standard The standard to use for the test. + * @param string $methodName The name of the missing method. + * + * @dataProvider dataExceptionIsThrownOnMissingInterfaceMethod + * + * @return void + */ + public function testExceptionIsThrownOnMissingInterfaceMethod($standard, $methodName) + { + // Set up the ruleset. + $standard = __DIR__.'/'.$standard; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = "`(^|\R)ERROR: Sniff class \S+Sniff is missing required method $methodName\(\)\.\R`"; + $this->expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testExceptionIsThrownOnMissingInterfaceMethod() + + + /** + * Data provider. + * + * @see testExceptionIsThrownOnMissingInterfaceMethod() + * + * @return array> + */ + public static function dataExceptionIsThrownOnMissingInterfaceMethod() + { + return [ + 'Missing register() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml', + 'methodName' => 'register', + ], + 'Missing process() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml', + 'methodName' => 'process', + ], + 'Missing both, checking register() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml', + 'methodName' => 'register', + ], + 'Missing both, checking process() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml', + 'methodName' => 'process', + ], + ]; + + }//end dataExceptionIsThrownOnMissingInterfaceMethod() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsTest.php new file mode 100644 index 00000000..1ed3ee18 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsTest.php @@ -0,0 +1,293 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::registerSniffs() method. + * + * @covers \PHP_CodeSniffer\Ruleset::registerSniffs + */ +final class RegisterSniffsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + /** + * Original value of the $sniffs property on the Ruleset. + * + * @var array + */ + private static $originalSniffs = []; + + /** + * List of Standards dir relative sniff files loaded for the PSR1 standard. + * + * @var array + */ + private static $psr1SniffFiles = [ + 'Generic/Sniffs/Files/ByteOrderMarkSniff.php', + 'Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php', + 'Generic/Sniffs/PHP/DisallowAlternativePHPTagsSniff.php', + 'Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php', + 'PSR1/Sniffs/Classes/ClassDeclarationSniff.php', + 'PSR1/Sniffs/Files/SideEffectsSniff.php', + 'PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php', + 'Squiz/Sniffs/Classes/ValidClassNameSniff.php', + ]; + + /** + * Absolute paths to the sniff files loaded for the PSR1 standard. + * + * @var array + */ + private static $psr1SniffAbsolutePaths = []; + + + /** + * Initialize the config and ruleset objects which will be used for some of these tests. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1']); + self::$ruleset = new Ruleset($config); + + // Remember the original value of the Ruleset::$sniff property as the tests adjust it. + self::$originalSniffs = self::$ruleset->sniffs; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + ksort(self::$originalSniffs); + + // Update the sniff file list. + $standardsDir = dirname(dirname(dirname(__DIR__))).DIRECTORY_SEPARATOR; + $standardsDir .= 'src'.DIRECTORY_SEPARATOR.'Standards'.DIRECTORY_SEPARATOR; + + self::$psr1SniffAbsolutePaths = self::relativeToAbsoluteSniffFiles($standardsDir, self::$psr1SniffFiles); + + }//end initializeConfigAndRuleset() + + + /** + * Convert relative paths to absolute paths and ensure the paths use the correct OS-specific directory separator. + * + * @param string $baseDir Directory to which these paths are relative to. Including trailing slash. + * @param array $relativePaths Relative paths. + * + * @return array + */ + public static function relativeToAbsoluteSniffFiles($baseDir, $relativePaths) + { + $fileList = []; + foreach ($relativePaths as $sniffName) { + $sniffFile = str_replace('/', DIRECTORY_SEPARATOR, $sniffName); + $sniffFile = $baseDir.$sniffFile; + $fileList[] = $sniffFile; + } + + return $fileList; + + }//end relativeToAbsoluteSniffFiles() + + + /** + * Clear out the Ruleset::$sniffs property. + * + * @before + * + * @return void + */ + protected function clearOutSniffs() + { + // Clear out the Ruleset::$sniffs property. + self::$ruleset->sniffs = []; + + }//end clearOutSniffs() + + + /** + * Test that registering sniffs works as expected (simple base test case). + * + * @return void + */ + public function testRegisteredSniffsShouldBeTheSame() + { + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsShouldBeTheSame() + + + /** + * Test that if only specific sniffs are requested, only those are registered. + * + * {@internal Can't test this via the CLI arguments due to some code in the Ruleset class + * related to sniff tests.} + * + * @return void + */ + public function testRegisteredSniffsWithRestrictions() + { + $restrictions = [ + 'psr1\\sniffs\\classes\\classdeclarationsniff' => true, + 'psr1\\sniffs\\files\\sideeffectssniff' => true, + 'psr1\\sniffs\\methods\\camelcapsmethodnamesniff' => true, + ]; + + $expected = [ + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + ]; + + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, $restrictions, []); + + $this->assertSame($expected, array_keys(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsWithRestrictions() + + + /** + * Test that sniffs excluded via the CLI are not registered. + * + * @return void + */ + public function testRegisteredSniffsWithExclusions() + { + // Set up the ruleset. + $args = [ + '--standard=PSR1', + '--exclude=PSR1.Classes.ClassDeclaration,PSR1.Files.SideEffects,PSR1.Methods.CamelCapsMethodName', + ]; + $config = new ConfigDouble($args); + $ruleset = new Ruleset($config); + + $expected = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ]; + + $actual = array_keys($ruleset->sniffs); + sort($actual); + + $this->assertSame($expected, $actual); + + }//end testRegisteredSniffsWithExclusions() + + + /** + * Test combining requesting specific sniffs and excluding a subset of those. + * + * @return void + */ + public function testRegisteredSniffsBothRestrictionsAndExclusions() + { + $restrictions = [ + 'generic\\sniffs\\namingconventions\\uppercaseconstantnamesniff' => true, + 'generic\\sniffs\\php\\disallowalternativephptagssniff' => true, + 'generic\\sniffs\\php\\disallowshortopentagsniff' => true, + 'psr1\\sniffs\\classes\\classdeclarationsniff' => true, + 'squiz\\sniffs\\classes\\validclassnamesniff' => true, + ]; + + $exclusions = [ + 'squiz\\sniffs\\classes\\validclassnamesniff' => true, + 'generic\\sniffs\\php\\disallowalternativephptagssniff' => true, + 'generic\\sniffs\\namingconventions\\uppercaseconstantnamesniff' => true, + ]; + + $expected = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + ]; + + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, $restrictions, $exclusions); + + $this->assertSame($expected, array_keys(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsBothRestrictionsAndExclusions() + + + /** + * Verify that abstract sniffs are filtered out and not registered. + * + * @return void + */ + public function testRegisterSniffsFiltersOutAbstractClasses() + { + $extraPathsBaseDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR; + $extraPaths = [ + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/AbstractSniff.php', + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryB/AnotherAbstractSniff.php', + ]; + $extraPaths = self::relativeToAbsoluteSniffFiles($extraPathsBaseDir, $extraPaths); + + $fileList = self::$psr1SniffAbsolutePaths; + foreach ($extraPaths as $path) { + $fileList[] = $path; + } + + self::$ruleset->registerSniffs($fileList, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisterSniffsFiltersOutAbstractClasses() + + + /** + * Test that sniff files not in a "/Sniffs/" directory are filtered out and not registered. + * + * @return void + */ + public function testRegisteredSniffsFiltersOutFilePathsWithoutSniffsDir() + { + $extraPathsBaseDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR; + $extraPaths = [ + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/NotInSniffsDirSniff.php', + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/SubDir/NotInSniffsDirSniff.php', + ]; + $extraPaths = self::relativeToAbsoluteSniffFiles($extraPathsBaseDir, $extraPaths); + + $fileList = self::$psr1SniffAbsolutePaths; + foreach ($extraPaths as $path) { + $fileList[] = $path; + } + + self::$ruleset->registerSniffs($fileList, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsFiltersOutFilePathsWithoutSniffsDir() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Runner/AbstractRunnerTestCase.php b/vendor/squizlabs/php_codesniffer/tests/Core/Runner/AbstractRunnerTestCase.php new file mode 100644 index 00000000..ae5905bc --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Runner/AbstractRunnerTestCase.php @@ -0,0 +1,19 @@ +markTestSkipped('This test needs CS mode to run'); + } + + $this->checkProgressDot($colors, $code, $sniffs, $expected); + + }//end testProgressDotCs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataProgressDotCs() + { + return [ + 'No colors: Dot: no errors, no warnings' => [ + 'colors' => false, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'No colors: E: has error' => [ + 'colors' => false, + 'code' => ' 'Generic.CodeAnalysis.RequireExplicitBooleanOperatorPrecedence', + 'expected' => 'E', + ], + 'No colors: W: has warning' => [ + 'colors' => false, + 'code' => ' 'Generic.Commenting.Todo', + 'expected' => 'W', + ], + + 'Colors: Dot: no errors, no warnings' => [ + 'colors' => true, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'Colors: E: has error (red)' => [ + 'colors' => true, + 'code' => ' 'Generic.CodeAnalysis.RequireExplicitBooleanOperatorPrecedence', + 'expected' => "\033[31m".'E'."\033[0m", + ], + 'Colors: E: has fixable error (green)' => [ + 'colors' => true, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax', + 'expected' => "\033[32m".'E'."\033[0m", + ], + 'Colors: W: has warning (yellow)' => [ + 'colors' => true, + 'code' => ' 'Generic.Commenting.Todo', + 'expected' => "\033[33m".'W'."\033[0m", + ], + 'Colors: W: has fixable warning (green)' => [ + 'colors' => true, + 'code' => ' 'Generic.CodeAnalysis.EmptyPHPStatement', + 'expected' => "\033[32m".'W'."\033[0m", + ], + ]; + + }//end dataProgressDotCs() + + + /** + * Verify the correct progress indicator is used for a file in CBF mode. + * + * @param bool $colors Whether to enable colors or not. + * @param string $code Code snippet to process. + * @param string $sniffs Comma-separated list of sniff(s) to run against the code snippet. + * @param string $expected Expected output of the progress printer. + * + * @dataProvider dataProgressDotCbf + * + * @group CBF + * + * @return void + */ + public function testProgressDotCbf($colors, $code, $sniffs, $expected) + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->checkProgressDot($colors, $code, $sniffs, $expected, true); + + }//end testProgressDotCbf() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataProgressDotCbf() + { + return [ + 'No colors: Dot: no errors, no warnings' => [ + 'colors' => false, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'No colors: F: fixes made' => [ + 'colors' => false, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax', + 'expected' => 'F', + ], + 'No colors: E: has fixer conflict' => [ + 'colors' => false, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax,Generic.Arrays.DisallowShortArraySyntax', + 'expected' => 'E', + ], + + 'Colors: Dot: no errors, no warnings (no color)' => [ + 'colors' => true, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'Colors: F: fixes made (green)' => [ + 'colors' => true, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax', + 'expected' => "\033[32m".'F'."\033[0m", + ], + 'Colors: E: has fixer conflict (red)' => [ + 'colors' => true, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax,Generic.Arrays.DisallowShortArraySyntax', + 'expected' => "\033[31m".'E'."\033[0m", + ], + ]; + + }//end dataProgressDotCbf() + + + /** + * Verify the correct progress indicator is used for a file in CBF mode. + * + * @param bool $colors Whether to enable colors or not. + * @param string $code Code snippet to process. + * @param string $sniffs Comma-separated list of sniff(s) to run against the code snippet. + * @param string $expected Expected output of the progress printer. + * @param bool $enableFixer Whether to fix the code or not. + * + * @return void + */ + private function checkProgressDot($colors, $code, $sniffs, $expected, $enableFixer=false) + { + $this->expectOutputString($expected); + + $config = new ConfigDouble(['-p']); + $config->colors = $colors; + $config->standards = ['Generic']; + $config->sniffs = explode(',', $sniffs); + $ruleset = new Ruleset($config); + + $runner = new Runner(); + $runner->config = $config; + + $file = new DummyFile($code, $ruleset, $config); + $file->process(); + + if ($enableFixer === true) { + $file->fixer->fixFile(); + } + + $runner->printProgress($file, 2, 1); + + }//end checkProgressDot() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Runner/PrintProgressTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Runner/PrintProgressTest.php new file mode 100644 index 00000000..93535417 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Runner/PrintProgressTest.php @@ -0,0 +1,235 @@ +standards = ['Generic']; + self::$config->sniffs = ['Generic.PHP.LowerCaseConstant']; + self::$ruleset = new Ruleset(self::$config); + + self::$runner = new Runner(); + self::$runner->config = self::$config; + + // Simple file which won't have any errors against the above sniff. + $content = 'process(); + + }//end initializeConfigRulesetRunner() + + + /** + * Reset some flags between tests. + * + * @after + * + * @return void + */ + protected function resetObjectFlags() + { + self::$config->showProgress = true; + self::$fileWithoutErrorsOrWarnings->ignored = false; + + }//end resetObjectFlags() + + + /** + * Destroy the Config object after the test to reset statics. + * + * @afterClass + * + * @return void + */ + public static function reset() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when this object is destroyed, but we can't definitively rely on that). + self::$config->__destruct(); + + }//end reset() + + + /** + * Verify that if progress reporting is disabled, no progress dots will show. + * + * @return void + */ + public function testNoProgressIsShownWhenDisabled() + { + $this->expectOutputString(''); + + self::$config->showProgress = false; + + for ($i = 1; $i <= 10; $i++) { + self::$runner->printProgress(self::$fileWithoutErrorsOrWarnings, 3, $i); + } + + }//end testNoProgressIsShownWhenDisabled() + + + /** + * Verify ignored files will be marked with an "S" for "skipped". + * + * @return void + */ + public function testProgressDotSkippedFiles() + { + $nrOfFiles = 10; + $this->expectOutputString('.S.S.S.S.S 10 / 10 (100%)'.PHP_EOL); + + for ($i = 1; $i <= $nrOfFiles; $i++) { + if (($i % 2) === 0) { + self::$fileWithoutErrorsOrWarnings->ignored = true; + } else { + self::$fileWithoutErrorsOrWarnings->ignored = false; + } + + self::$runner->printProgress(self::$fileWithoutErrorsOrWarnings, $nrOfFiles, $i); + } + + }//end testProgressDotSkippedFiles() + + + /** + * Verify the handling of the summary at the end of each line. + * + * @param int $nrOfFiles The number of files in the scan. + * @param string $expected The expected progress information output. + * + * @dataProvider dataEndOfLineSummary + * + * @return void + */ + public function testEndOfLineSummary($nrOfFiles, $expected) + { + $this->expectOutputString($expected); + + for ($i = 1; $i <= $nrOfFiles; $i++) { + self::$runner->printProgress(self::$fileWithoutErrorsOrWarnings, $nrOfFiles, $i); + } + + }//end testEndOfLineSummary() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataEndOfLineSummary() + { + $fullLineOfDots = str_repeat('.', 60); + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Favour test readability. + return [ + 'Less than 60 files (23)' => [ + 'nrOfFiles' => 23, + 'expected' => str_repeat('.', 23).' 23 / 23 (100%)'.PHP_EOL, + ], + 'Exactly 60 files' => [ + 'nrOfFiles' => 60, + 'expected' => $fullLineOfDots.' 60 / 60 (100%)'.PHP_EOL, + ], + 'Between 60 and 120 files (71)' => [ + 'nrOfFiles' => 71, + 'expected' => $fullLineOfDots.' 60 / 71 (85%)'.PHP_EOL + .str_repeat('.', 11).str_repeat(' ', 49).' 71 / 71 (100%)'.PHP_EOL, + ], + 'More than 120 files (162)' => [ + 'nrOfFiles' => 162, + 'expected' => $fullLineOfDots.' 60 / 162 (37%)'.PHP_EOL + .$fullLineOfDots.' 120 / 162 (74%)'.PHP_EOL + .str_repeat('.', 42).str_repeat(' ', 18).' 162 / 162 (100%)'.PHP_EOL, + ], + // More than anything, this tests that the padding of the numbers is handled correctly. + 'More than 1000 files (1234)' => [ + 'nrOfFiles' => 1234, + 'expected' => $fullLineOfDots.' 60 / 1234 (5%)'.PHP_EOL + .$fullLineOfDots.' 120 / 1234 (10%)'.PHP_EOL + .$fullLineOfDots.' 180 / 1234 (15%)'.PHP_EOL + .$fullLineOfDots.' 240 / 1234 (19%)'.PHP_EOL + .$fullLineOfDots.' 300 / 1234 (24%)'.PHP_EOL + .$fullLineOfDots.' 360 / 1234 (29%)'.PHP_EOL + .$fullLineOfDots.' 420 / 1234 (34%)'.PHP_EOL + .$fullLineOfDots.' 480 / 1234 (39%)'.PHP_EOL + .$fullLineOfDots.' 540 / 1234 (44%)'.PHP_EOL + .$fullLineOfDots.' 600 / 1234 (49%)'.PHP_EOL + .$fullLineOfDots.' 660 / 1234 (53%)'.PHP_EOL + .$fullLineOfDots.' 720 / 1234 (58%)'.PHP_EOL + .$fullLineOfDots.' 780 / 1234 (63%)'.PHP_EOL + .$fullLineOfDots.' 840 / 1234 (68%)'.PHP_EOL + .$fullLineOfDots.' 900 / 1234 (73%)'.PHP_EOL + .$fullLineOfDots.' 960 / 1234 (78%)'.PHP_EOL + .$fullLineOfDots.' 1020 / 1234 (83%)'.PHP_EOL + .$fullLineOfDots.' 1080 / 1234 (88%)'.PHP_EOL + .$fullLineOfDots.' 1140 / 1234 (92%)'.PHP_EOL + .$fullLineOfDots.' 1200 / 1234 (97%)'.PHP_EOL + .str_repeat('.', 34).str_repeat(' ', 26).' 1234 / 1234 (100%)'.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataEndOfLineSummary() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSExplainTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSExplainTest.php new file mode 100644 index 00000000..479fe5ce --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSExplainTest.php @@ -0,0 +1,73 @@ + + * @copyright 2023 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Runner; + +use PHP_CodeSniffer\Runner; +use PHP_CodeSniffer\Tests\Core\Runner\AbstractRunnerTestCase; + +/** + * Tests the wiring in of the explain functionality in the Runner class. + * + * @covers \PHP_CodeSniffer\Runner::runPHPCS + */ +final class RunPHPCSExplainTest extends AbstractRunnerTestCase +{ + + + /** + * Test that each standard passed on the command-line is explained separately. + * + * @return void + */ + public function testExplainWillExplainEachStandardSeparately() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $standard = dirname(__DIR__).'/Ruleset/ExplainSingleSniffTest.xml'; + $_SERVER['argv'] = [ + 'phpcs', + '-e', + "--standard=PSR1,$standard", + '--report-width=80', + ]; + + $expected = PHP_EOL; + $expected .= 'The PSR1 standard contains 8 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (3 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Files.SideEffects'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL.PHP_EOL; + + $expected .= 'The ExplainSingleSniffTest standard contains 1 sniff'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Scope.MethodScope'.PHP_EOL; + + $this->expectOutputString($expected); + + $runner = new Runner(); + $runner->runPHPCS(); + + }//end testExplainWillExplainEachStandardSeparately() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSGeneratorTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSGeneratorTest.php new file mode 100644 index 00000000..0bc89f22 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSGeneratorTest.php @@ -0,0 +1,72 @@ +markTestSkipped('This test needs CS mode to run'); + } + + $standard = dirname(__DIR__).'/Generators/OneDocTest.xml'; + $_SERVER['argv'] = [ + 'phpcs', + '--generator=Text', + "--standard=$standard,PSR1", + '--report-width=80', + ]; + + $regex = '`^ + \R* # Optional blank line at the start. + (?: + (?P-++\R) # Line with dashes. + \|[ ]GENERATORTEST[ ]CODING[ ]STANDARD:[ ][^\|]+\|\R # Doc title line with prefix expected for first standard. + (?P>delimiter) # Line with dashes. + \R(?:[^\r\n]+\R)+\R{2} # Standard description. + ) # Only expect this group once. + (?: + (?P>delimiter) # Line with dashes. + \|[ ]PSR1[ ]CODING[ ]STANDARD:[ ][^\|]+\|\R # Doc title line with prefix expected for second standard. + (?P>delimiter) # Line with dashes. + \R(?:[^\r\n]+\R)+\R # Standard description. + (?: + -+[ ]CODE[ ]COMPARISON[ ]-+\R # Code Comparison starter line with dashes. + (?:(?:[^\r\n]+\R)+(?P>delimiter)){2} # Arbitrary text followed by a delimiter line. + )* # Code comparison is optional and can exist multiple times. + \R+ + ){3,} # This complete group should occur at least three times. + `x'; + + $this->expectOutputRegex($regex); + + $runner = new Runner(); + $runner->runPHPCS(); + + }//end testGeneratorWillShowEachStandardSeparately() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Standards/StandardRulesetsQATest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Standards/StandardRulesetsQATest.php new file mode 100644 index 00000000..baba4574 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Standards/StandardRulesetsQATest.php @@ -0,0 +1,82 @@ +assertSame('', $seenOutput); + + // Make sure sniffs were registered. + $this->assertGreaterThanOrEqual(1, count($ruleset->sniffCodes)); + + }//end testBuildInStandardsDoNotContainErrors() + + + /** + * Data provider. + * + * @see self::testBuildInStandardsDoNotContainErrors() + * + * @return array> + */ + public static function dataBuildInStandards() + { + // Get a list of all build-in, PHPCS native standards. + $sep = DIRECTORY_SEPARATOR; + $targetDir = dirname(dirname(dirname(__DIR__))).$sep.'src'.$sep.'Standards'.$sep; + $rulesetFiles = glob($targetDir.'*'.$sep.'ruleset.xml'); + + $data = []; + foreach ($rulesetFiles as $file) { + $standardName = basename(dirname($file)); + $data[$standardName] = [ + 'standard' => $standardName, + ]; + } + + return $data; + + }//end dataBuildInStandards() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/AbstractTokenizerTestCase.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/AbstractTokenizerTestCase.php new file mode 100644 index 00000000..f3daf2bf --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/AbstractTokenizerTestCase.php @@ -0,0 +1,147 @@ + + * @copyright 2018-2019 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers; + +use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHPUnit\Framework\TestCase; +use ReflectionProperty; + +abstract class AbstractTokenizerTestCase extends TestCase +{ + + /** + * The file extension of the test case file (without leading dot). + * + * This allows child classes to overrule the default `inc` with, for instance, + * `js` or `css` when applicable. + * + * @var string + */ + protected $fileExtension = 'inc'; + + /** + * The tab width setting to use when tokenizing the file. + * + * This allows for test case files to use a different tab width than the default. + * + * @var integer + */ + protected $tabWidth = 4; + + /** + * The \PHP_CodeSniffer\Files\File object containing the parsed contents of the test case file. + * + * @var \PHP_CodeSniffer\Files\File + */ + protected $phpcsFile; + + + /** + * Initialize & tokenize \PHP_CodeSniffer\Files\File with code from the test case file. + * + * The test case file for a unit test class has to be in the same directory + * directory and use the same file name as the test class, using the .inc extension. + * + * @before + * + * @return void + */ + protected function initializeFile() + { + if (isset($this->phpcsFile) === false) { + $_SERVER['argv'] = []; + $config = new ConfigDouble(); + + // Also set a tab-width to enable testing tab-replaced vs `orig_content`. + $config->tabWidth = $this->tabWidth; + + $ruleset = new Ruleset($config); + + // Default to a file with the same name as the test class. Extension is property based. + $relativeCN = str_replace(__NAMESPACE__, '', get_called_class()); + $relativePath = str_replace('\\', DIRECTORY_SEPARATOR, $relativeCN); + $pathToTestFile = realpath(__DIR__).$relativePath.'.'.$this->fileExtension; + + // Make sure the file gets parsed correctly based on the file type. + $contents = 'phpcs_input_file: '.$pathToTestFile.PHP_EOL; + $contents .= file_get_contents($pathToTestFile); + + $this->phpcsFile = new DummyFile($contents, $ruleset, $config); + $this->phpcsFile->parse(); + }//end if + + }//end initializeFile() + + + /** + * Test QA: verify that a test case file does not contain any duplicate test markers. + * + * When a test case file contains a lot of test cases, it is easy to overlook that a test marker name + * is already in use. + * A test wouldn't necessarily fail on this, but would not be testing what is intended to be tested as + * it would be verifying token properties for the wrong token. + * + * This test safeguards against this. + * + * @coversNothing + * + * @return void + */ + public function testTestMarkersAreUnique() + { + AbstractMethodUnitTest::assertTestMarkersAreUnique($this->phpcsFile); + + }//end testTestMarkersAreUnique() + + + /** + * Get the token pointer for a target token based on a specific comment found on the line before. + * + * Note: the test delimiter comment MUST start with "/* test" to allow this function to + * distinguish between comments used *in* a test and test delimiters. + * + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. + * + * @return int + */ + protected function getTargetToken($commentString, $tokenType, $tokenContent=null) + { + return AbstractMethodUnitTest::getTargetTokenFromFile($this->phpcsFile, $commentString, $tokenType, $tokenContent); + + }//end getTargetToken() + + + /** + * Clear the static "resolved tokens" cache property on the Tokenizer\PHP class. + * + * This method should be used selectively by tests to ensure the code under test is actually hit + * by the test testing the code. + * + * @return void + */ + public static function clearResolvedTokensCache() + { + $property = new ReflectionProperty('PHP_CodeSniffer\Tokenizers\PHP', 'resolveTokenCache'); + $property->setAccessible(true); + $property->setValue(null, []); + $property->setAccessible(false); + + }//end clearResolvedTokensCache() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/CommentTestCase.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/CommentTestCase.php new file mode 100644 index 00000000..625029db --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/CommentTestCase.php @@ -0,0 +1,117 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Base class for testing DocBlock comment tokenization. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +abstract class CommentTestCase extends AbstractTokenizerTestCase +{ + + + /** + * Test whether the docblock opener and closer have the expected extra keys. + * + * @param string $marker The comment prefacing the target token. + * @param int $closerOffset The offset of the closer from the opener. + * @param array $expectedTags The expected tags offsets array. + * + * @dataProvider dataDocblockOpenerCloser + * + * @return void + */ + public function testDocblockOpenerCloser($marker, $closerOffset, $expectedTags) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($marker, [T_DOC_COMMENT_OPEN_TAG]); + + $opener = $tokens[$target]; + + $this->assertArrayHasKey('comment_closer', $opener, 'Comment opener: comment_closer index is not set'); + $this->assertArrayHasKey('comment_tags', $opener, 'Comment opener: comment_tags index is not set'); + + $expectedCloser = ($target + $closerOffset); + $this->assertSame($expectedCloser, $opener['comment_closer'], 'Comment opener: comment_closer not set to the expected stack pointer'); + + // Update the tags expectations. + foreach ($expectedTags as $i => $ptr) { + $expectedTags[$i] += $target; + } + + $this->assertSame($expectedTags, $opener['comment_tags'], 'Comment opener: recorded tags do not match expected tags'); + + $closer = $tokens[$opener['comment_closer']]; + + $this->assertArrayHasKey('comment_opener', $closer, 'Comment closer: comment_opener index is not set'); + $this->assertSame($target, $closer['comment_opener'], 'Comment closer: comment_opener not set to the expected stack pointer'); + + }//end testDocblockOpenerCloser() + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + abstract public static function dataDocblockOpenerCloser(); + + + /** + * Test helper. Check a token sequence complies with an expected token sequence. + * + * @param int $startPtr The position in the file to start checking from. + * @param array> $expectedSequence The consecutive token constants and their contents to expect. + * + * @return void + */ + protected function checkTokenSequence($startPtr, array $expectedSequence) + { + $tokens = $this->phpcsFile->getTokens(); + + $sequenceKey = 0; + $sequenceCount = count($expectedSequence); + + for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++, $sequenceKey++) { + $currentItem = $expectedSequence[$sequenceKey]; + $expectedCode = key($currentItem); + $expectedType = Tokens::tokenName($expectedCode); + $expectedContent = current($currentItem); + $errorMsgSuffix = PHP_EOL.'(StackPtr: '.$i.' | Position in sequence: '.$sequenceKey.' | Expected: '.$expectedType.')'; + + $this->assertSame( + $expectedCode, + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedType.' (code)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedType, + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedType.' (type)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedContent, + $tokens[$i]['content'], + 'Token content did not match expectations'.$errorMsgSuffix + ); + }//end for + + }//end checkTokenSequence() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding1Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding1Test.inc new file mode 100644 index 00000000..a43c7d9b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding1Test.inc @@ -0,0 +1,6 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding1Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock, no blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 8, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Unclosed docblock, live coding.... with no blank line at end of file.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding2Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding2Test.inc new file mode 100644 index 00000000..b113645b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding2Test.inc @@ -0,0 +1,5 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding2Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock with blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 7, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Unclosed docblock, live coding.... with a blank line at end of file.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_CLOSE_TAG => ''], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding3Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding3Test.inc new file mode 100644 index 00000000..9b81a434 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding3Test.inc @@ -0,0 +1,4 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding3Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock, no contents, no blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 1, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_CLOSE_TAG => ''], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding4Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding4Test.inc new file mode 100644 index 00000000..1561e715 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding4Test.inc @@ -0,0 +1,7 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding4Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock, trailing whitespace on last line, no blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 15, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'The last line of this test must have trailing whitespace.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'So, be careful when saving this file!'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => ''], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/MultiLineDocBlockTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/MultiLineDocBlockTest.inc new file mode 100644 index 00000000..f33afcd6 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/MultiLineDocBlockTest.inc @@ -0,0 +1,81 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that multiline docblocks are tokenized correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class MultiLineDocBlockTest extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'Multi line docblock: no contents' => [ + 'marker' => '/* testEmptyDocblock */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Multi line docblock: variety of text and tags' => [ + 'marker' => '/* testMultilineDocblock */', + 'closerOffset' => 95, + // phpcs:ignore Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed + 'expectedTags' => [21, 29, 36, 46, 56, 63, 73, 80, 90], + ], + 'Multi line docblock: no leading stars' => [ + 'marker' => '/* testMultilineDocblockNoStars */', + 'closerOffset' => 32, + // phpcs:ignore Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed + 'expectedTags' => [10, 16, 21, 27], + ], + 'Multi line docblock: indented' => [ + 'marker' => '/* testMultilineDocblockIndented */', + 'closerOffset' => 60, + // phpcs:ignore Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed + 'expectedTags' => [21, 28, 38, 45, 55], + ], + 'Multi line docblock: opener not on own line' => [ + 'marker' => '/* testMultilineDocblockOpenerNotOnOwnLine */', + 'closerOffset' => 10, + 'expectedTags' => [], + ], + 'Multi line docblock: closer not on own line' => [ + 'marker' => '/* testMultilineDocblockCloserNotOnOwnLine */', + 'closerOffset' => 11, + 'expectedTags' => [], + ], + 'Multi line docblock: stars not aligned' => [ + 'marker' => '/* testMultilineDocblockStarsNotAligned */', + 'closerOffset' => 26, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of an empty, multi-line DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testEmptyDocblock() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyDocblock() + + + /** + * Verify tokenization of a multi-line DocBlock containing all possible tokens. + * + * @return void + */ + public function testMultilineDocblock() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'This is a multi-line docblock.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With blank lines, stars, tags, and tag descriptions.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagWithoutDescription'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@since'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '10.3'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@deprecated'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '11.5'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@requires'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'PHP 7.1 -- PHPUnit tag.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag-with-dashes-is-suppported'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag_with_underscores'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'string $p1 Description 1.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'int|false $p2 Description 2.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@return'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'void'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblock() + + + /** + * Verify tokenization of a multi-line DocBlock with extra starts for the opener/closer and no stars on the lines between. + * + * @return void + */ + public function testMultilineDocblockNoStars() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/****'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'This is a multi-line docblock, but the lines are not marked with stars.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Then again, the opener and closer have an abundance of stars.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@since'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '10.3'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'string $p1 Description 1.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'int|false $p2 Description 2.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@return'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'void'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '**/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockNoStars() + + + /** + * Verify tokenization of a multi-line, indented DocBlock. + * + * @return void + */ + public function testMultilineDocblockIndented() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'This is a multi-line indented docblock.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With blank lines, stars, tags, and tag descriptions.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@since'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '10.3'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@deprecated'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '11.5'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'string $p1 Description 1.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'int|false $p2 Description 2.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@return'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'void'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockIndented() + + + /** + * Verify tokenization of a multi-line DocBlock, where the opener is not on its own line. + * + * @return void + */ + public function testMultilineDocblockOpenerNotOnOwnLine() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Start of description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'description continued.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockOpenerNotOnOwnLine() + + + /** + * Verify tokenization of a multi-line DocBlock, where the closer is not on its own line. + * + * @return void + */ + public function testMultilineDocblockCloserNotOnOwnLine() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Start of description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'description continued. '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockCloserNotOnOwnLine() + + + /** + * Verify tokenization of a multi-line DocBlock with inconsistent indentation. + * + * @return void + */ + public function testMultilineDocblockStarsNotAligned() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Start of description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Line below this is missing a star.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Text'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Star indented.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Closer indented.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockStarsNotAligned() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/PhpcsAnnotationsInDocBlockTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/PhpcsAnnotationsInDocBlockTest.inc new file mode 100644 index 00000000..d74f68d2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/PhpcsAnnotationsInDocBlockTest.inc @@ -0,0 +1,116 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that PHPCS native annotations in docblocks are tokenized correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class PhpcsAnnotationsInDocBlockTest extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'Single-line: @phpcs:ignoreFile annotation' => [ + 'marker' => '/* testSingleLineDocIgnoreFileAnnotation */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single-line: @phpcs:ignore annotation' => [ + 'marker' => '/* testSingleLineDocIgnoreAnnotation */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single-line: @phpcs:disable annotation' => [ + 'marker' => '/* testSingleLineDocDisableAnnotation */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single-line: @phpcs:enable annotation; no whitespace' => [ + 'marker' => '/* testSingleLineDocEnableAnnotationNoWhitespace */', + 'closerOffset' => 2, + 'expectedTags' => [], + ], + + 'Multi-line: @phpcs:ignoreFile at the start' => [ + 'marker' => '/* testMultiLineDocIgnoreFileAnnotationAtStart */', + 'closerOffset' => 13, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:ignore at the start' => [ + 'marker' => '/* testMultiLineDocIgnoreAnnotationAtStart */', + 'closerOffset' => 13, + 'expectedTags' => [10], + ], + 'Multi-line: @phpcs:disable at the start' => [ + 'marker' => '/* testMultiLineDocDisableAnnotationAtStart */', + 'closerOffset' => 13, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:enable at the start' => [ + 'marker' => '/* testMultiLineDocEnableAnnotationAtStart */', + 'closerOffset' => 18, + 'expectedTags' => [13], + ], + + 'Multi-line: @phpcs:ignoreFile in the middle' => [ + 'marker' => '/* testMultiLineDocIgnoreFileAnnotationInMiddle */', + 'closerOffset' => 21, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:ignore in the middle' => [ + 'marker' => '/* testMultiLineDocIgnoreAnnotationInMiddle */', + 'closerOffset' => 23, + 'expectedTags' => [5], + ], + 'Multi-line: @phpcs:disable in the middle' => [ + 'marker' => '/* testMultiLineDocDisableAnnotationInMiddle */', + 'closerOffset' => 26, + 'expectedTags' => [21], + ], + 'Multi-line: @phpcs:enable in the middle' => [ + 'marker' => '/* testMultiLineDocEnableAnnotationInMiddle */', + 'closerOffset' => 24, + 'expectedTags' => [21], + ], + + 'Multi-line: @phpcs:ignoreFile at the end' => [ + 'marker' => '/* testMultiLineDocIgnoreFileAnnotationAtEnd */', + 'closerOffset' => 16, + 'expectedTags' => [5], + ], + 'Multi-line: @phpcs:ignore at the end' => [ + 'marker' => '/* testMultiLineDocIgnoreAnnotationAtEnd */', + 'closerOffset' => 16, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:disable at the end' => [ + 'marker' => '/* testMultiLineDocDisableAnnotationAtEnd */', + 'closerOffset' => 18, + 'expectedTags' => [5], + ], + 'Multi-line: @phpcs:enable at the end' => [ + 'marker' => '/* testMultiLineDocEnableAnnotationAtEnd */', + 'closerOffset' => 16, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testSingleLineDocIgnoreFileAnnotation() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocIgnoreFileAnnotation() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation. + * + * @return void + */ + public function testSingleLineDocIgnoreAnnotation() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName -- With reason '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocIgnoreAnnotation() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation. + * + * @return void + */ + public function testSingleLineDocDisableAnnotation() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName,Stnd.Other '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocDisableAnnotation() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation. + * + * @return void + */ + public function testSingleLineDocEnableAnnotationNoWhitespace() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat.SniffName'], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocEnableAnnotationNoWhitespace() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation at the start. + * + * @return void + */ + public function testMultiLineDocIgnoreFileAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreFileAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation at the start. + * + * @return void + */ + public function testMultiLineDocIgnoreAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation at the start. + * + * @return void + */ + public function testMultiLineDocDisableAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName -- Ensure PHPCS annotations are also retokenized correctly.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocDisableAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation at the start. + * + * @return void + */ + public function testMultiLineDocEnableAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat,Stnd.Other'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocEnableAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation in the middle. + * + * @return void + */ + public function testMultiLineDocIgnoreFileAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreFileAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation in the middle. + * + * @return void + */ + public function testMultiLineDocIgnoreAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagBefore'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With Description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation in the middle. + * + * @return void + */ + public function testMultiLineDocDisableAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName -- Ensure PHPCS annotations are also retokenized correctly.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagAfter'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With Description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocDisableAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation in the middle. + * + * @return void + */ + public function testMultiLineDocEnableAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat,Stnd.Other'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagAfter'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocEnableAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation at the end. + * + * @return void + */ + public function testMultiLineDocIgnoreFileAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagBefore'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreFileAnnotationAtEnd() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation at the end. + * + * @return void + */ + public function testMultiLineDocIgnoreAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreAnnotationAtEnd() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation at the end. + * + * @return void + */ + public function testMultiLineDocDisableAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagBefore'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With Description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName -- Ensure PHPCS annotations are also retokenized correctly.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocDisableAnnotationAtEnd() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation at the end. + * + * @return void + */ + public function testMultiLineDocEnableAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat,Stnd.Other'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocEnableAnnotationAtEnd() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/SingleLineDocBlockTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/SingleLineDocBlockTest.inc new file mode 100644 index 00000000..88b05ea4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/SingleLineDocBlockTest.inc @@ -0,0 +1,26 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that single line docblocks are tokenized correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class SingleLineDocBlockTest extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'Single line docblock: empty, no whitespace' => [ + 'marker' => '/* testEmptyDocblockNoWhiteSpace */', + 'closerOffset' => 1, + 'expectedTags' => [], + ], + 'Single line docblock: only whitespace' => [ + 'marker' => '/* testEmptyDocblockWithWhiteSpace */', + 'closerOffset' => 2, + 'expectedTags' => [], + ], + 'Single line docblock: just text' => [ + 'marker' => '/* testSingleLineDocblockNoTag */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single line docblock: @var type before name' => [ + 'marker' => '/* testSingleLineDocblockWithTag1 */', + 'closerOffset' => 5, + 'expectedTags' => [2], + ], + 'Single line docblock: @var name before type' => [ + 'marker' => '/* testSingleLineDocblockWithTag2 */', + 'closerOffset' => 5, + 'expectedTags' => [2], + ], + 'Single line docblock: @see with description' => [ + 'marker' => '/* testSingleLineDocblockWithTag3 */', + 'closerOffset' => 5, + 'expectedTags' => [2], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify an empty block comment is tokenized as T_COMMENT, not as a docblock. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testEmptyBlockCommentNoWhiteSpace() + { + $expectedSequence = [ + [T_COMMENT => '/**/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', [T_COMMENT, T_DOC_COMMENT_OPEN_TAG]); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyBlockCommentNoWhiteSpace() + + + /** + * Verify tokenization of an empty, single line DocBlock without whitespace between the opener and closer. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testEmptyDocblockNoWhiteSpace() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyDocblockNoWhiteSpace() + + + /** + * Verify tokenization of an empty, single line DocBlock. + * + * @return void + */ + public function testEmptyDocblockWithWhiteSpace() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyDocblockWithWhiteSpace() + + + /** + * Verify tokenization of a single line DocBlock. + * + * @return void + */ + public function testSingleLineDocblockNoTag() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Just some text '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockNoTag() + + + /** + * Verify tokenization of a single line DocBlock with a tag. + * + * @return void + */ + public function testSingleLineDocblockWithTag1() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@var'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '\SomeClass[] $var '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockWithTag1() + + + /** + * Verify tokenization of a single line DocBlock with a tag. + * + * @return void + */ + public function testSingleLineDocblockWithTag2() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@var'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '$var \SomeClass[] '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockWithTag2() + + + /** + * Verify tokenization of a single line DocBlock with a tag. + * + * @return void + */ + public function testSingleLineDocblockWithTag3() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@see'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something::Else '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockWithTag3() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.inc new file mode 100644 index 00000000..3ee1afd0 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.inc @@ -0,0 +1,29 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class AnonClassParenthesisOwnerTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that anonymous class tokens without parenthesis do not get assigned a parenthesis owner. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataAnonClassNoParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testAnonClassNoParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); + $this->assertArrayNotHasKey('parenthesis_owner', $tokens[$anonClass]); + $this->assertArrayNotHasKey('parenthesis_opener', $tokens[$anonClass]); + $this->assertArrayNotHasKey('parenthesis_closer', $tokens[$anonClass]); + + }//end testAnonClassNoParentheses() + + + /** + * Test that the next open/close parenthesis after an anonymous class without parenthesis + * do not get assigned the anonymous class as a parenthesis owner. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataAnonClassNoParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testAnonClassNoParenthesesNextOpenClose($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $function = $this->getTargetToken($testMarker, T_FUNCTION); + + $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener]); + $this->assertSame($function, $tokens[$opener]['parenthesis_owner']); + + $closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer]); + $this->assertSame($function, $tokens[$closer]['parenthesis_owner']); + + }//end testAnonClassNoParenthesesNextOpenClose() + + + /** + * Data provider. + * + * @see testAnonClassNoParentheses() + * @see testAnonClassNoParenthesesNextOpenClose() + * + * @return array> + */ + public static function dataAnonClassNoParentheses() + { + return [ + 'plain' => [ + 'testMarker' => '/* testNoParentheses */', + ], + 'readonly' => [ + 'testMarker' => '/* testReadonlyNoParentheses */', + ], + 'declaration contains comments and extra whitespace' => [ + 'testMarker' => '/* testNoParenthesesAndEmptyTokens */', + ], + ]; + + }//end dataAnonClassNoParentheses() + + + /** + * Test that anonymous class tokens with parenthesis get assigned a parenthesis owner, + * opener and closer; and that the opener/closer get the anonymous class assigned as owner. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataAnonClassWithParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testAnonClassWithParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); + $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); + $closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); + + $this->assertArrayHasKey('parenthesis_owner', $tokens[$anonClass]); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$anonClass]); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$anonClass]); + $this->assertSame($anonClass, $tokens[$anonClass]['parenthesis_owner']); + $this->assertSame($opener, $tokens[$anonClass]['parenthesis_opener']); + $this->assertSame($closer, $tokens[$anonClass]['parenthesis_closer']); + + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener]); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$opener]); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$opener]); + $this->assertSame($anonClass, $tokens[$opener]['parenthesis_owner']); + $this->assertSame($opener, $tokens[$opener]['parenthesis_opener']); + $this->assertSame($closer, $tokens[$opener]['parenthesis_closer']); + + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer]); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$closer]); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$closer]); + $this->assertSame($anonClass, $tokens[$closer]['parenthesis_owner']); + $this->assertSame($opener, $tokens[$closer]['parenthesis_opener']); + $this->assertSame($closer, $tokens[$closer]['parenthesis_closer']); + + }//end testAnonClassWithParentheses() + + + /** + * Data provider. + * + * @see testAnonClassWithParentheses() + * + * @return array> + */ + public static function dataAnonClassWithParentheses() + { + return [ + 'plain' => [ + 'testMarker' => '/* testWithParentheses */', + ], + 'readonly' => [ + 'testMarker' => '/* testReadonlyWithParentheses */', + ], + 'declaration contains comments and extra whitespace' => [ + 'testMarker' => '/* testWithParenthesesAndEmptyTokens */', + ], + ]; + + }//end dataAnonClassWithParentheses() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.inc new file mode 100644 index 00000000..6d8adfcb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.inc @@ -0,0 +1,58 @@ + 10); + +/* testArrayWithComment */ +$var = Array /*comment*/ (1 => 10); + +/* testNestingArray */ +$var = array( + /* testNestedArray */ + array( + 'key' => 'value', + + /* testClosureReturnType */ + 'closure' => function($a) use($global) : Array {}, + ), +); + +/* testFunctionDeclarationParamType */ +function typedParam(array $a) {} + +/* testFunctionDeclarationReturnType */ +function returnType($a) : int|array|null {} + +class Bar { + /* testClassConst */ + const ARRAY = []; + + /* testClassMethod */ + public function array() {} + + /* testOOConstType */ + const array /* testTypedOOConstName */ ARRAY = /* testOOConstDefault */ array(); + + /* testOOPropertyType */ + protected array $property; +} + +class DNFTypes { + /* testOOConstDNFType */ + const (A&B)|array|(C&D) NAME = []; + + /* testOOPropertyDNFType */ + protected (A&B)|ARRAY|null $property; + + /* testFunctionDeclarationParamDNFType */ + public function name(null|array|(A&B) $param) { + /* testClosureDeclarationParamDNFType */ + $cl = function ( array|(A&B) $param) {}; + + /* testArrowDeclarationReturnDNFType */ + $arrow = fn($a): (A&B)|Array => new $a; + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.php new file mode 100644 index 00000000..f94971d9 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.php @@ -0,0 +1,200 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class ArrayKeywordTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the array keyword is correctly tokenized as `T_ARRAY`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (code)'); + $this->assertSame('T_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (type)'); + + }//end testArrayKeyword() + + + /** + * Data provider. + * + * @see testArrayKeyword() + * + * @return array> + */ + public static function dataArrayKeyword() + { + return [ + 'empty array' => [ + 'testMarker' => '/* testEmptyArray */', + ], + 'array with space before parenthesis' => [ + 'testMarker' => '/* testArrayWithSpace */', + ], + 'array with comment before parenthesis' => [ + 'testMarker' => '/* testArrayWithComment */', + 'testContent' => 'Array', + ], + 'nested: outer array' => [ + 'testMarker' => '/* testNestingArray */', + ], + 'nested: inner array' => [ + 'testMarker' => '/* testNestedArray */', + ], + 'OO constant default value' => [ + 'testMarker' => '/* testOOConstDefault */', + ], + ]; + + }//end dataArrayKeyword() + + + /** + * Test that the array keyword when used in a type declaration is correctly tokenized as `T_STRING`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayType + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testArrayType($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testArrayType() + + + /** + * Data provider. + * + * @see testArrayType() + * + * @return array> + */ + public static function dataArrayType() + { + return [ + 'closure return type' => [ + 'testMarker' => '/* testClosureReturnType */', + 'testContent' => 'Array', + ], + 'function param type' => [ + 'testMarker' => '/* testFunctionDeclarationParamType */', + ], + 'function union return type' => [ + 'testMarker' => '/* testFunctionDeclarationReturnType */', + ], + 'OO constant type' => [ + 'testMarker' => '/* testOOConstType */', + ], + 'OO property type' => [ + 'testMarker' => '/* testOOPropertyType */', + ], + + 'OO constant DNF type' => [ + 'testMarker' => '/* testOOConstDNFType */', + ], + 'OO property DNF type' => [ + 'testMarker' => '/* testOOPropertyDNFType */', + 'testContent' => 'ARRAY', + ], + 'function param DNF type' => [ + 'testMarker' => '/* testFunctionDeclarationParamDNFType */', + ], + 'closure param DNF type' => [ + 'testMarker' => '/* testClosureDeclarationParamDNFType */', + ], + 'arrow return DNF type' => [ + 'testMarker' => '/* testArrowDeclarationReturnDNFType */', + 'testContent' => 'Array', + ], + ]; + + }//end dataArrayType() + + + /** + * Verify that the retokenization of `T_ARRAY` tokens to `T_STRING` is handled correctly + * for tokens with the contents 'array' which aren't in actual fact the array keyword. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNotArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotArrayKeyword() + + + /** + * Data provider. + * + * @see testNotArrayKeyword() + * + * @return array> + */ + public static function dataNotArrayKeyword() + { + return [ + 'class-constant-name' => [ + 'testMarker' => '/* testClassConst */', + 'testContent' => 'ARRAY', + ], + 'class-method-name' => [ + 'testMarker' => '/* testClassMethod */', + ], + 'class-constant-name-after-type' => [ + 'testMarker' => '/* testTypedOOConstName */', + 'testContent' => 'ARRAY', + ], + ]; + + }//end dataNotArrayKeyword() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.inc new file mode 100644 index 00000000..9d56c095 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.inc @@ -0,0 +1,90 @@ + 'foobar'])] +function attribute_with_params_on_function_test() {} + +/* testAttributeWithShortClosureParameter */ +#[AttributeWithParams(static fn ($value) => ! $value)] +function attribute_with_short_closure_param_test() {} + +/* testTwoAttributeOnTheSameLine */ +#[CustomAttribute] #[AttributeWithParams('foo')] +function two_attribute_on_same_line_test() {} + +/* testAttributeAndCommentOnTheSameLine */ +#[CustomAttribute] // This is a comment +function attribute_and_line_comment_on_same_line_test() {} + +/* testAttributeGrouping */ +#[CustomAttribute, AttributeWithParams('foo'), AttributeWithParams('foo', bar: ['bar' => 'foobar'])] +function attribute_grouping_test() {} + +/* testAttributeMultiline */ +#[ + CustomAttribute, + AttributeWithParams('foo'), + AttributeWithParams('foo', bar: ['bar' => 'foobar']) +] +function attribute_multiline_test() {} + +/* testAttributeMultilineWithComment */ +#[ + CustomAttribute, // comment + AttributeWithParams(/* another comment */ 'foo'), + AttributeWithParams('foo', bar: ['bar' => 'foobar']) +] +function attribute_multiline_with_comment_test() {} + +/* testSingleAttributeOnParameter */ +function single_attribute_on_parameter_test(#[ParamAttribute] int $param) {} + +/* testMultipleAttributesOnParameter */ +function multiple_attributes_on_parameter_test(#[ParamAttribute, AttributeWithParams(/* another comment */ 'foo')] int $param) {} + +/* testFqcnAttribute */ +#[Boo\QualifiedName, \Foo\FullyQualifiedName('foo')] +function fqcn_attribute_test() {} + +/* testNestedAttributes */ +#[Boo\QualifiedName(fn (#[AttributeOne('boo')] $value) => (string) $value)] +function nested_attributes_test() {} + +/* testMultilineAttributesOnParameter */ +function multiline_attributes_on_parameter_test(#[ + AttributeWithParams( + 'foo' + ) + ] int $param) {} + +/* testAttributeContainingTextLookingLikeCloseTag */ +#[DeprecationReason('reason: ')] +function attribute_containing_text_looking_like_close_tag() {} + +/* testAttributeContainingMultilineTextLookingLikeCloseTag */ +#[DeprecationReason( + 'reason: ' +)] +function attribute_containing_mulitline_text_looking_like_close_tag() {} + +/* testInvalidAttribute */ +#[ThisIsNotAnAttribute +function invalid_attribute_test() {} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.php new file mode 100644 index 00000000..bc15a193 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.php @@ -0,0 +1,700 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class AttributesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that attributes are parsed correctly. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $tokenCodes The codes of tokens inside the attributes. + * + * @dataProvider dataAttribute + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testAttribute($testMarker, $tokenCodes) + { + $tokens = $this->phpcsFile->getTokens(); + + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $length = (count($tokenCodes) + 1); + + $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(($attribute + $length), $closer); + + $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); + + $this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']); + $this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']); + + $map = array_map( + function ($token) use ($attribute, $length) { + $this->assertArrayHasKey('attribute_closer', $token); + $this->assertSame(($attribute + $length), $token['attribute_closer']); + + return $token['code']; + }, + array_slice($tokens, ($attribute + 1), ($length - 1)) + ); + + $this->assertSame($tokenCodes, $map); + + }//end testAttribute() + + + /** + * Data provider. + * + * @see testAttribute() + * + * @return array>> + */ + public static function dataAttribute() + { + return [ + 'class attribute' => [ + 'testMarker' => '/* testAttribute */', + 'tokenCodes' => [ + T_STRING, + ], + ], + 'class attribute with param' => [ + 'testMarker' => '/* testAttributeWithParams */', + 'tokenCodes' => [ + T_STRING, + T_OPEN_PARENTHESIS, + T_STRING, + T_DOUBLE_COLON, + T_STRING, + T_CLOSE_PARENTHESIS, + ], + ], + 'class attribute with named param' => [ + 'testMarker' => '/* testAttributeWithNamedParam */', + 'tokenCodes' => [ + T_STRING, + T_OPEN_PARENTHESIS, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_STRING, + T_DOUBLE_COLON, + T_STRING, + T_CLOSE_PARENTHESIS, + ], + ], + 'function attribute' => [ + 'testMarker' => '/* testAttributeOnFunction */', + 'tokenCodes' => [ + T_STRING, + ], + ], + 'function attribute with params' => [ + 'testMarker' => '/* testAttributeOnFunctionWithParams */', + 'tokenCodes' => [ + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_COMMA, + T_WHITESPACE, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_OPEN_SHORT_ARRAY, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_DOUBLE_ARROW, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_SHORT_ARRAY, + T_CLOSE_PARENTHESIS, + ], + ], + 'function attribute with arrow function as param' => [ + 'testMarker' => '/* testAttributeWithShortClosureParameter */', + 'tokenCodes' => [ + T_STRING, + T_OPEN_PARENTHESIS, + T_STATIC, + T_WHITESPACE, + T_FN, + T_WHITESPACE, + T_OPEN_PARENTHESIS, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_FN_ARROW, + T_WHITESPACE, + T_BOOLEAN_NOT, + T_WHITESPACE, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + ], + ], + 'function attribute; multiple comma separated classes' => [ + 'testMarker' => '/* testAttributeGrouping */', + 'tokenCodes' => [ + T_STRING, + T_COMMA, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + T_COMMA, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_COMMA, + T_WHITESPACE, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_OPEN_SHORT_ARRAY, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_DOUBLE_ARROW, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_SHORT_ARRAY, + T_CLOSE_PARENTHESIS, + ], + ], + 'function attribute; multiple comma separated classes, one per line' => [ + 'testMarker' => '/* testAttributeMultiline */', + 'tokenCodes' => [ + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_COMMA, + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + T_COMMA, + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_COMMA, + T_WHITESPACE, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_OPEN_SHORT_ARRAY, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_DOUBLE_ARROW, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_SHORT_ARRAY, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + ], + ], + 'function attribute; multiple comma separated classes, one per line, with comments' => [ + 'testMarker' => '/* testAttributeMultilineWithComment */', + 'tokenCodes' => [ + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_COMMA, + T_WHITESPACE, + T_COMMENT, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_COMMENT, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + T_COMMA, + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_COMMA, + T_WHITESPACE, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_OPEN_SHORT_ARRAY, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_DOUBLE_ARROW, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_SHORT_ARRAY, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + ], + ], + 'function attribute; using partially qualified and fully qualified class names' => [ + 'testMarker' => '/* testFqcnAttribute */', + 'tokenCodes' => [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_COMMA, + T_WHITESPACE, + T_NS_SEPARATOR, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + ], + ], + ]; + + }//end dataAttribute() + + + /** + * Test that multiple attributes on the same line are parsed correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testTwoAttributesOnTheSameLine() + { + $tokens = $this->phpcsFile->getTokens(); + + $attribute = $this->getTargetToken('/* testTwoAttributeOnTheSameLine */', T_ATTRIBUTE); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']); + $this->assertSame(T_ATTRIBUTE, $tokens[($closer + 2)]['code']); + $this->assertArrayHasKey('attribute_closer', $tokens[($closer + 2)]); + + }//end testTwoAttributesOnTheSameLine() + + + /** + * Test that attribute followed by a line comment is parsed correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testAttributeAndLineComment() + { + $tokens = $this->phpcsFile->getTokens(); + + $attribute = $this->getTargetToken('/* testAttributeAndCommentOnTheSameLine */', T_ATTRIBUTE); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']); + $this->assertSame(T_COMMENT, $tokens[($closer + 2)]['code']); + + }//end testAttributeAndLineComment() + + + /** + * Test that attributes on function declaration parameters are parsed correctly. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int $position The token position (starting from T_FUNCTION) of T_ATTRIBUTE token. + * @param array $tokenCodes The codes of tokens inside the attributes. + * + * @dataProvider dataAttributeOnParameters + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testAttributeOnParameters($testMarker, $position, array $tokenCodes) + { + $tokens = $this->phpcsFile->getTokens(); + + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $length = (count($tokenCodes) + 1); + + $function = $this->getTargetToken($testMarker, T_FUNCTION); + $attribute = ($function + $position); + + $this->assertSame(T_ATTRIBUTE, $tokens[$attribute]['code']); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $this->assertSame(($attribute + $length), $tokens[$attribute]['attribute_closer']); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']); + $this->assertSame(T_STRING, $tokens[($closer + 2)]['code']); + $this->assertSame('int', $tokens[($closer + 2)]['content']); + + $this->assertSame(T_VARIABLE, $tokens[($closer + 4)]['code']); + $this->assertSame('$param', $tokens[($closer + 4)]['content']); + + $map = array_map( + function ($token) use ($attribute, $length) { + $this->assertArrayHasKey('attribute_closer', $token); + $this->assertSame(($attribute + $length), $token['attribute_closer']); + + return $token['code']; + }, + array_slice($tokens, ($attribute + 1), ($length - 1)) + ); + + $this->assertSame($tokenCodes, $map); + + }//end testAttributeOnParameters() + + + /** + * Data provider. + * + * @see testAttributeOnParameters() + * + * @return array>> + */ + public static function dataAttributeOnParameters() + { + return [ + 'parameter attribute; single, inline' => [ + 'testMarker' => '/* testSingleAttributeOnParameter */', + 'position' => 4, + 'tokenCodes' => [ + T_STRING, + ], + ], + 'parameter attribute; multiple comma separated, inline' => [ + 'testMarker' => '/* testMultipleAttributesOnParameter */', + 'position' => 4, + 'tokenCodes' => [ + T_STRING, + T_COMMA, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_COMMENT, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + ], + ], + 'parameter attribute; single, multiline' => [ + 'testMarker' => '/* testMultilineAttributesOnParameter */', + 'position' => 4, + 'tokenCodes' => [ + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_WHITESPACE, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_WHITESPACE, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_WHITESPACE, + ], + ], + ]; + + }//end dataAttributeOnParameters() + + + /** + * Test that an attribute containing text which looks like a PHP close tag is tokenized correctly. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array> $expectedTokensAttribute The codes of tokens inside the attributes. + * @param array $expectedTokensAfter The codes of tokens after the attributes. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @dataProvider dataAttributeOnTextLookingLikeCloseTag + * + * @return void + */ + public function testAttributeContainingTextLookingLikeCloseTag($testMarker, array $expectedTokensAttribute, array $expectedTokensAfter) + { + $tokens = $this->phpcsFile->getTokens(); + + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $length = count($expectedTokensAttribute); + + $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); + + $this->assertSame('T_ATTRIBUTE', $tokens[$attribute]['type']); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(($attribute + $length), $closer); + $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); + $this->assertSame('T_ATTRIBUTE_END', $tokens[$closer]['type']); + + $this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']); + $this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']); + + $i = ($attribute + 1); + foreach ($expectedTokensAttribute as $item) { + list($expectedType, $expectedContents) = $item; + $this->assertSame($expectedType, $tokens[$i]['type']); + $this->assertSame($expectedContents, $tokens[$i]['content']); + $this->assertArrayHasKey('attribute_opener', $tokens[$i]); + $this->assertArrayHasKey('attribute_closer', $tokens[$i]); + ++$i; + } + + $i = ($closer + 1); + foreach ($expectedTokensAfter as $expectedCode) { + $this->assertSame($expectedCode, $tokens[$i]['code']); + ++$i; + } + + }//end testAttributeContainingTextLookingLikeCloseTag() + + + /** + * Data provider. + * + * @see dataAttributeOnTextLookingLikeCloseTag() + * + * @return array>|array>> + */ + public static function dataAttributeOnTextLookingLikeCloseTag() + { + return [ + 'function attribute; string param with "?>"' => [ + 'testMarker' => '/* testAttributeContainingTextLookingLikeCloseTag */', + 'expectedTokensAttribute' => [ + [ + 'T_STRING', + 'DeprecationReason', + ], + [ + 'T_OPEN_PARENTHESIS', + '(', + ], + [ + 'T_CONSTANT_ENCAPSED_STRING', + "'reason: '", + ], + [ + 'T_CLOSE_PARENTHESIS', + ')', + ], + [ + 'T_ATTRIBUTE_END', + ']', + ], + ], + 'expectedTokensAfter' => [ + T_WHITESPACE, + T_FUNCTION, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + ], + ], + 'function attribute; string param with "?>"; multiline' => [ + 'testMarker' => '/* testAttributeContainingMultilineTextLookingLikeCloseTag */', + 'expectedTokensAttribute' => [ + [ + 'T_STRING', + 'DeprecationReason', + ], + [ + 'T_OPEN_PARENTHESIS', + '(', + ], + [ + 'T_WHITESPACE', + "\n", + ], + [ + 'T_WHITESPACE', + " ", + ], + [ + 'T_CONSTANT_ENCAPSED_STRING', + "'reason: '", + ], + [ + 'T_WHITESPACE', + "\n", + ], + [ + 'T_CLOSE_PARENTHESIS', + ')', + ], + [ + 'T_ATTRIBUTE_END', + ']', + ], + ], + 'expectedTokensAfter' => [ + T_WHITESPACE, + T_FUNCTION, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + ], + ], + ]; + + }//end dataAttributeOnTextLookingLikeCloseTag() + + + /** + * Test that invalid attribute (or comment starting with #[ and without ]) are parsed correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testInvalidAttribute() + { + $tokens = $this->phpcsFile->getTokens(); + + $attribute = $this->getTargetToken('/* testInvalidAttribute */', T_ATTRIBUTE); + + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + $this->assertNull($tokens[$attribute]['attribute_closer']); + + }//end testInvalidAttribute() + + + /** + * Test that nested attributes are parsed correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * @covers PHP_CodeSniffer\Tokenizers\PHP::createAttributesNestingMap + * + * @return void + */ + public function testNestedAttributes() + { + $tokens = $this->phpcsFile->getTokens(); + $tokenCodes = [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_OPEN_PARENTHESIS, + T_FN, + T_WHITESPACE, + T_OPEN_PARENTHESIS, + T_ATTRIBUTE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + T_ATTRIBUTE_END, + T_WHITESPACE, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_FN_ARROW, + T_WHITESPACE, + T_STRING_CAST, + T_WHITESPACE, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + ]; + + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $outerAttributeLength = (count($tokenCodes) + 1); + + $attribute = $this->getTargetToken('/* testNestedAttributes */', T_ATTRIBUTE); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(($attribute + $outerAttributeLength), $closer); + + $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); + + $this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']); + $this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']); + + $this->assertArrayNotHasKey('nested_attributes', $tokens[$attribute]); + $this->assertArrayHasKey('nested_attributes', $tokens[($attribute + 8)]); + $this->assertSame([$attribute => ($attribute + $outerAttributeLength)], $tokens[($attribute + 8)]['nested_attributes']); + + $test = function (array $tokens, $outerAttributeLength, $nestedMap) use ($attribute) { + foreach ($tokens as $token) { + $this->assertArrayHasKey('attribute_closer', $token); + $this->assertSame(($attribute + $outerAttributeLength), $token['attribute_closer']); + $this->assertSame($nestedMap, $token['nested_attributes']); + } + }; + + // Length here is 8 (nested attribute offset) + 5 (real length). + $innerAttributeLength = (8 + 5); + + $test(array_slice($tokens, ($attribute + 1), 7), $outerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + $test(array_slice($tokens, ($attribute + 8), 1), $innerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + + $test( + array_slice($tokens, ($attribute + 9), 4), + $innerAttributeLength, + [ + $attribute => $attribute + $outerAttributeLength, + $attribute + 8 => $attribute + 13, + ] + ); + + $test(array_slice($tokens, ($attribute + 13), 1), $innerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + $test(array_slice($tokens, ($attribute + 14), 10), $outerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + + $map = array_map( + static function ($token) { + return $token['code']; + }, + array_slice($tokens, ($attribute + 1), ($outerAttributeLength - 1)) + ); + + $this->assertSame($tokenCodes, $map); + + }//end testNestedAttributes() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillAsymmetricVisibilityTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillAsymmetricVisibilityTest.inc new file mode 100644 index 00000000..aaf050ad --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillAsymmetricVisibilityTest.inc @@ -0,0 +1,60 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the support of PHP 8.4 asymmetric visibility. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + */ +final class BackfillAsymmetricVisibilityTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the asymmetric visibility keywords are tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testType The expected token type + * @param string $testContent The token content to look for + * + * @dataProvider dataAsymmetricVisibility + * + * @return void + */ + public function testAsymmetricVisibility($testMarker, $testType, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken( + $testMarker, + [ + T_PUBLIC_SET, + T_PROTECTED_SET, + T_PRIVATE_SET, + ] + ); + $tokenArray = $tokens[$target]; + + $this->assertSame( + $testType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].' (type)' + ); + $this->assertSame( + constant($testType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].' (code)' + ); + $this->assertSame( + $testContent, + $tokenArray['content'], + 'Token tokenized as '.$tokenArray['type'].' (content)' + ); + + }//end testAsymmetricVisibility() + + + /** + * Data provider. + * + * @see testAsymmetricVisibility() + * + * @return array> + */ + public static function dataAsymmetricVisibility() + { + return [ + // Normal property declarations. + 'property, public set, no read visibility, lowercase' => [ + 'testMarker' => '/* testPublicSetProperty */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'public(set)', + ], + 'property, public set, no read visibility, uppercase' => [ + 'testMarker' => '/* testPublicSetPropertyUC */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'PUBLIC(SET)', + ], + 'property, public set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicPublicSetProperty */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'public(set)', + ], + 'property, public set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicPublicSetPropertyUC */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'PUBLIC(SET)', + ], + 'property, protected set, no read visibility, lowercase' => [ + 'testMarker' => '/* testProtectedSetProperty */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'protected(set)', + ], + 'property, protected set, no read visibility, uppercase' => [ + 'testMarker' => '/* testProtectedSetPropertyUC */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'PROTECTED(SET)', + ], + 'property, protected set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicProtectedSetProperty */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'protected(set)', + ], + 'property, protected set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicProtectedSetPropertyUC */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'PROTECTED(SET)', + ], + 'property, private set, no read visibility, lowercase' => [ + 'testMarker' => '/* testPrivateSetProperty */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'private(set)', + ], + 'property, private set, no read visibility, uppercase' => [ + 'testMarker' => '/* testPrivateSetPropertyUC */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'PRIVATE(SET)', + ], + 'property, private set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicPrivateSetProperty */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'private(set)', + ], + 'property, private set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicPrivateSetPropertyUC */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'PRIVATE(SET)', + ], + + // Constructor property promotion. + 'promotion, public set, no read visibility, lowercase' => [ + 'testMarker' => '/* testPublicSetCPP */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'public(set)', + ], + 'promotion, public set, no read visibility, uppercase' => [ + 'testMarker' => '/* testPublicSetCPPUC */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'PUBLIC(SET)', + ], + 'promotion, public set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicPublicSetCPP */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'public(set)', + ], + 'promotion, public set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicPublicSetCPPUC */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'PUBLIC(SET)', + ], + 'promotion, protected set, no read visibility, lowercase' => [ + 'testMarker' => '/* testProtectedSetCPP */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'protected(set)', + ], + 'promotion, protected set, no read visibility, uppercase' => [ + 'testMarker' => '/* testProtectedSetCPPUC */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'PROTECTED(SET)', + ], + 'promotion, protected set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicProtectedSetCPP */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'protected(set)', + ], + 'promotion, protected set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicProtectedSetCPPUC */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'PROTECTED(SET)', + ], + 'promotion, private set, no read visibility, lowercase' => [ + 'testMarker' => '/* testPrivateSetCPP */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'private(set)', + ], + 'promotion, private set, no read visibility, uppercase' => [ + 'testMarker' => '/* testPrivateSetCPPUC */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'PRIVATE(SET)', + ], + 'promotion, private set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicPrivateSetCPP */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'private(set)', + ], + 'promotion, private set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicPrivateSetCPPUC */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'PRIVATE(SET)', + ], + ]; + + }//end dataAsymmetricVisibility() + + + /** + * Test that things that are not asymmetric visibility keywords are not + * tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testType The expected token type + * @param string $testContent The token content to look for + * + * @dataProvider dataNotAsymmetricVisibility + * + * @return void + */ + public function testNotAsymmetricVisibility($testMarker, $testType, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken( + $testMarker, + [constant($testType)], + $testContent + ); + $tokenArray = $tokens[$target]; + + $this->assertSame( + $testType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].' (type)' + ); + $this->assertSame( + constant($testType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].' (code)' + ); + + }//end testNotAsymmetricVisibility() + + + /** + * Data provider. + * + * @see testNotAsymmetricVisibility() + * + * @return array> + */ + public static function dataNotAsymmetricVisibility() + { + return [ + 'property, invalid case 1' => [ + 'testMarker' => '/* testInvalidUnsetProperty */', + 'testType' => 'T_PUBLIC', + 'testContent' => 'public', + ], + 'property, invalid case 2' => [ + 'testMarker' => '/* testInvalidSpaceProperty */', + 'testType' => 'T_PUBLIC', + 'testContent' => 'public', + ], + 'property, invalid case 3' => [ + 'testMarker' => '/* testInvalidCommentProperty */', + 'testType' => 'T_PROTECTED', + 'testContent' => 'protected', + ], + 'property, invalid case 4' => [ + 'testMarker' => '/* testInvalidGetProperty */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + 'property, invalid case 5' => [ + 'testMarker' => '/* testInvalidNoParenProperty */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + + // Constructor property promotion. + 'promotion, invalid case 1' => [ + 'testMarker' => '/* testInvalidUnsetCPP */', + 'testType' => 'T_PUBLIC', + 'testContent' => 'public', + ], + 'promotion, invalid case 2' => [ + 'testMarker' => '/* testInvalidSpaceCPP */', + 'testType' => 'T_PUBLIC', + 'testContent' => 'public', + ], + 'promotion, invalid case 3' => [ + 'testMarker' => '/* testInvalidCommentCPP */', + 'testType' => 'T_PROTECTED', + 'testContent' => 'protected', + ], + 'promotion, invalid case 4' => [ + 'testMarker' => '/* testInvalidGetCPP */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + 'promotion, invalid case 5' => [ + 'testMarker' => '/* testInvalidNoParenCPP */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + + // Context sensitivitiy. + 'protected as function name' => [ + 'testMarker' => '/* testProtectedFunctionName */', + 'testType' => 'T_STRING', + 'testContent' => 'protected', + ], + 'public as function name' => [ + 'testMarker' => '/* testPublicFunctionName */', + 'testType' => 'T_STRING', + 'testContent' => 'public', + ], + 'set as parameter type' => [ + 'testMarker' => '/* testSetParameterType */', + 'testType' => 'T_STRING', + 'testContent' => 'Set', + ], + + // Live coding. + 'live coding' => [ + 'testMarker' => '/* testLiveCoding */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + ]; + + }//end dataNotAsymmetricVisibility() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.inc new file mode 100644 index 00000000..16624ecc --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.inc @@ -0,0 +1,91 @@ +enum = 'foo'; + } +} + +/* testEnumUsedAsFunctionName */ +function enum() +{ +} + +/* testDeclarationContainingComment */ +enum /* comment */ Name +{ + case SOME_CASE; +} + +/* testEnumUsedAsNamespaceName */ +namespace Enum; +/* testEnumUsedAsPartOfNamespaceName */ +namespace My\Enum\Collection; +/* testEnumUsedInObjectInitialization */ +$obj = new Enum; +/* testEnumAsFunctionCall */ +$var = enum($a, $b); +/* testEnumAsFunctionCallWithNamespace */ +var = namespace\enum(); +/* testClassConstantFetchWithEnumAsClassName */ +echo Enum::CONSTANT; +/* testClassConstantFetchWithEnumAsConstantName */ +echo ClassName::ENUM; + +/* testParseErrorMissingName */ +enum { + case SOME_CASE; +} + +/* testParseErrorLiveCoding */ +// This must be the last test in the file. +enum diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.php new file mode 100644 index 00000000..9b313ca6 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.php @@ -0,0 +1,226 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillEnumTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the "enum" keyword is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testContent The token content to look for. + * @param int $openerOffset Offset to find expected scope opener. + * @param int $closerOffset Offset to find expected scope closer. + * + * @dataProvider dataEnums + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testEnums($testMarker, $testContent, $openerOffset, $closerOffset) + { + $tokens = $this->phpcsFile->getTokens(); + $enum = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); + $tokenArray = $tokens[$enum]; + + $this->assertSame(T_ENUM, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM (code)'); + $this->assertSame('T_ENUM', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM (type)'); + + $this->assertArrayHasKey('scope_condition', $tokenArray); + $this->assertArrayHasKey('scope_opener', $tokenArray); + $this->assertArrayHasKey('scope_closer', $tokenArray); + + $this->assertSame($enum, $tokenArray['scope_condition']); + + $scopeOpener = $tokenArray['scope_opener']; + $scopeCloser = $tokenArray['scope_closer']; + + $expectedScopeOpener = ($enum + $openerOffset); + $expectedScopeCloser = ($enum + $closerOffset); + + $this->assertSame($expectedScopeOpener, $scopeOpener); + $this->assertArrayHasKey('scope_condition', $tokens[$scopeOpener]); + $this->assertArrayHasKey('scope_opener', $tokens[$scopeOpener]); + $this->assertArrayHasKey('scope_closer', $tokens[$scopeOpener]); + $this->assertSame($enum, $tokens[$scopeOpener]['scope_condition']); + $this->assertSame($scopeOpener, $tokens[$scopeOpener]['scope_opener']); + $this->assertSame($scopeCloser, $tokens[$scopeOpener]['scope_closer']); + + $this->assertSame($expectedScopeCloser, $scopeCloser); + $this->assertArrayHasKey('scope_condition', $tokens[$scopeCloser]); + $this->assertArrayHasKey('scope_opener', $tokens[$scopeCloser]); + $this->assertArrayHasKey('scope_closer', $tokens[$scopeCloser]); + $this->assertSame($enum, $tokens[$scopeCloser]['scope_condition']); + $this->assertSame($scopeOpener, $tokens[$scopeCloser]['scope_opener']); + $this->assertSame($scopeCloser, $tokens[$scopeCloser]['scope_closer']); + + }//end testEnums() + + + /** + * Data provider. + * + * @see testEnums() + * + * @return array> + */ + public static function dataEnums() + { + return [ + 'enum - pure' => [ + 'testMarker' => '/* testPureEnum */', + 'testContent' => 'enum', + 'openerOffset' => 4, + 'closerOffset' => 12, + ], + 'enum - backed int' => [ + 'testMarker' => '/* testBackedIntEnum */', + 'testContent' => 'enum', + 'openerOffset' => 7, + 'closerOffset' => 29, + ], + 'enum - backed string' => [ + 'testMarker' => '/* testBackedStringEnum */', + 'testContent' => 'enum', + 'openerOffset' => 8, + 'closerOffset' => 30, + ], + 'enum - backed int + implements' => [ + 'testMarker' => '/* testComplexEnum */', + 'testContent' => 'enum', + 'openerOffset' => 11, + 'closerOffset' => 72, + ], + 'enum keyword when "enum" is the name for the construct (yes, this is allowed)' => [ + 'testMarker' => '/* testEnumWithEnumAsClassName */', + 'testContent' => 'enum', + 'openerOffset' => 6, + 'closerOffset' => 7, + ], + 'enum - keyword is case insensitive' => [ + 'testMarker' => '/* testEnumIsCaseInsensitive */', + 'testContent' => 'EnUm', + 'openerOffset' => 4, + 'closerOffset' => 5, + ], + 'enum - declaration containing comment' => [ + 'testMarker' => '/* testDeclarationContainingComment */', + 'testContent' => 'enum', + 'openerOffset' => 6, + 'closerOffset' => 14, + ], + ]; + + }//end dataEnums() + + + /** + * Test that "enum" when not used as the keyword is still tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotEnums + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNotEnums($testMarker, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotEnums() + + + /** + * Data provider. + * + * @see testNotEnums() + * + * @return array> + */ + public static function dataNotEnums() + { + return [ + 'not enum - construct named enum' => [ + 'testMarker' => '/* testEnumAsClassNameAfterEnumKeyword */', + 'testContent' => 'Enum', + ], + 'not enum - class named enum' => [ + 'testMarker' => '/* testEnumUsedAsClassName */', + 'testContent' => 'Enum', + ], + 'not enum - class constant named enum' => [ + 'testMarker' => '/* testEnumUsedAsClassConstantName */', + 'testContent' => 'ENUM', + ], + 'not enum - method named enum' => [ + 'testMarker' => '/* testEnumUsedAsMethodName */', + 'testContent' => 'enum', + ], + 'not enum - class property named enum' => [ + 'testMarker' => '/* testEnumUsedAsPropertyName */', + 'testContent' => 'enum', + ], + 'not enum - global function named enum' => [ + 'testMarker' => '/* testEnumUsedAsFunctionName */', + 'testContent' => 'enum', + ], + 'not enum - namespace named enum' => [ + 'testMarker' => '/* testEnumUsedAsNamespaceName */', + 'testContent' => 'Enum', + ], + 'not enum - part of namespace named enum' => [ + 'testMarker' => '/* testEnumUsedAsPartOfNamespaceName */', + 'testContent' => 'Enum', + ], + 'not enum - class instantiation for class enum' => [ + 'testMarker' => '/* testEnumUsedInObjectInitialization */', + 'testContent' => 'Enum', + ], + 'not enum - function call' => [ + 'testMarker' => '/* testEnumAsFunctionCall */', + 'testContent' => 'enum', + ], + 'not enum - namespace relative function call' => [ + 'testMarker' => '/* testEnumAsFunctionCallWithNamespace */', + 'testContent' => 'enum', + ], + 'not enum - class constant fetch with enum as class name' => [ + 'testMarker' => '/* testClassConstantFetchWithEnumAsClassName */', + 'testContent' => 'Enum', + ], + 'not enum - class constant fetch with enum as constant name' => [ + 'testMarker' => '/* testClassConstantFetchWithEnumAsConstantName */', + 'testContent' => 'ENUM', + ], + 'parse error, not enum - enum declaration without name' => [ + 'testMarker' => '/* testParseErrorMissingName */', + 'testContent' => 'enum', + ], + 'parse error, not enum - enum declaration with curlies' => [ + 'testMarker' => '/* testParseErrorLiveCoding */', + 'testContent' => 'enum', + ], + ]; + + }//end dataNotEnums() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.inc new file mode 100644 index 00000000..eb907ed3 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.inc @@ -0,0 +1,31 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillExplicitOctalNotationTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that explicitly-defined octal values are tokenized as a single number and not as a number and a string. + * + * @param string $marker The comment which prefaces the target token in the test file. + * @param string $value The expected content of the token. + * @param int|string $nextToken The expected next token. + * @param string $nextContent The expected content of the next token. + * + * @dataProvider dataExplicitOctalNotation + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testExplicitOctalNotation($marker, $value, $nextToken, $nextContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $number = $this->getTargetToken($marker, [T_LNUMBER]); + + $this->assertSame($value, $tokens[$number]['content'], 'Content of integer token does not match expectation'); + + $this->assertSame($nextToken, $tokens[($number + 1)]['code'], 'Next token is not the expected type, but '.$tokens[($number + 1)]['type']); + $this->assertSame($nextContent, $tokens[($number + 1)]['content'], 'Next token did not have the expected contents'); + + }//end testExplicitOctalNotation() + + + /** + * Data provider. + * + * @see testExplicitOctalNotation() + * + * @return array> + */ + public static function dataExplicitOctalNotation() + { + return [ + 'Explicit octal' => [ + 'marker' => '/* testExplicitOctal */', + 'value' => '0o137041', + 'nextToken' => T_SEMICOLON, + 'nextContent' => ';', + ], + 'Explicit octal - capitalized O' => [ + 'marker' => '/* testExplicitOctalCapitalised */', + 'value' => '0O137041', + 'nextToken' => T_SEMICOLON, + 'nextContent' => ';', + ], + 'Explicit octal - with numeric literal separator' => [ + 'marker' => '/* testExplicitOctalWithNumericSeparator */', + 'value' => '0o137_041', + 'nextToken' => T_SEMICOLON, + 'nextContent' => ';', + ], + 'Invalid explicit octal - numeric literal separator directly after "0o"' => [ + 'marker' => '/* testInvalid1 */', + 'value' => '0', + 'nextToken' => T_STRING, + 'nextContent' => 'o_137', + ], + 'Invalid explicit octal - numeric literal separator directly after "0O" (capitalized O)' => [ + 'marker' => '/* testInvalid2 */', + 'value' => '0', + 'nextToken' => T_STRING, + 'nextContent' => 'O_41', + ], + 'Invalid explicit octal - number out of octal range' => [ + 'marker' => '/* testInvalid3 */', + 'value' => '0', + 'nextToken' => T_STRING, + 'nextContent' => 'o91', + ], + 'Invalid explicit octal - part of the number out of octal range' => [ + 'marker' => '/* testInvalid4 */', + 'value' => '0O2', + 'nextToken' => T_LNUMBER, + 'nextContent' => '82', + ], + 'Invalid explicit octal - part of the number out of octal range with numeric literal separator after' => [ + 'marker' => '/* testInvalid5 */', + 'value' => '0o2', + 'nextToken' => T_LNUMBER, + 'nextContent' => '8_2', + ], + 'Invalid explicit octal - part of the number out of octal range with numeric literal separator before' => [ + 'marker' => '/* testInvalid6 */', + 'value' => '0o2', + 'nextToken' => T_STRING, + 'nextContent' => '_82', + ], + 'Invalid explicit octal - explicit notation without number' => [ + 'marker' => '/* testInvalid7 */', + 'value' => '0', + 'nextToken' => T_STRING, + 'nextContent' => 'o', + ], + ]; + + }//end dataExplicitOctalNotation() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc new file mode 100644 index 00000000..ce247e99 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc @@ -0,0 +1,5 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillFnTokenParseErrorTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that un unfinished arrow function during live coding doesn't cause a "Undefined array key "parenthesis_closer"" error. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnfinishedArrowFunction() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testLiveCoding */', [T_STRING, T_FN], 'fn'); + $tokenArray = $tokens[$token]; + + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testUnfinishedArrowFunction() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.inc new file mode 100644 index 00000000..8930d4fb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.inc @@ -0,0 +1,228 @@ + $x + $y; + +/* testMixedCase */ +$fn1 = Fn($x) => $x + $y; + +/* testWhitespace */ +$fn1 = fn ($x) => $x + $y; + +/* testComment */ +$fn1 = fn /* comment here */ ($x) => $x + $y; + +/* testHeredoc */ +$fn1 = fn() => << /* testNestedInner */ fn($y) => $x * $y + $z; + +/* testNestedSharedCloserOuter */ +$foo = foo(fn() => /* testNestedSharedCloserInner */ fn() => bar() === true); + +/* testFunctionCall */ +$extended = fn($c) => $callable($factory($c), $c); + +/* testChainedFunctionCall */ +$result = Collection::from([1, 2]) + ->map(fn($v) => $v * 2) + ->reduce(/* testFunctionArgument */ fn($tmp, $v) => $tmp + $v, 0); + +/* testClosure */ +$extended = fn($c) => $callable(function() { + for ($x = 1; $x < 10; $x++) { + echo $x; + } + + echo 'done'; +}, $c); + +/* testArrayIndex */ +$found = in_array_cb($needle, $haystack, fn($array, $needle) => $array[2] === $needle); + +$result = array_map( + /* testReturnType */ + static fn(int $number) : int => $number + 1, + $numbers +); + +/* testReference */ +fn&($x) => $x; + +/* testGrouped */ +(fn($x) => $x) + $y; + +/* testArrayValue */ +$a = [ + 'a' => fn() => return 1, +]; + +/* testArrayValueNoTrailingComma */ +$a = [ + 'a' => fn() => foo() +]; + +/* testYield */ +$a = fn($x) => yield 'k' => $x; + +/* testNullableUnqualifiedClassName */ +$a = fn(?\DateTime $x) : ?\DateTime => $x; + +/* testNamespaceRelativeClassNameInTypes */ +$fn = fn(namespace\Foo $a) : ?namespace\Foo => $a; + +/* testSelfReturnType */ +fn(self $a) : self => $a; + +/* testParentReturnType */ +fn(parent $a) : parent => $a; + +/* testCallableReturnType */ +fn(callable $a) : callable => $a; + +/* testArrayReturnType */ +fn(array $a) : array => $a; + +/* testStaticReturnType */ +fn(array $a) : static => $a; + +/* testFalseReturnType */ +fn(array $a) : false => $a; + +/* testTrueReturnType */ +fn(array $a) : True => $a; + +/* testNullReturnType */ +fn(array $a) : null => $a; + +/* testUnionParamType */ +$arrowWithUnionParam = fn(int|float $param) : SomeClass => new SomeClass($param); + +/* testUnionReturnType */ +$arrowWithUnionReturn = fn($param) : int|float => $param | 10; + +/* testUnionReturnTypeWithTrue */ +$arrowWithUnionReturn = fn($param) : int|true => $param | 10; + +/* testUnionReturnTypeWithFalse */ +$arrowWithUnionReturn = fn($param) : string|FALSE => $param | 10; + +/* testIntersectionParamType */ +$arrowWithIntersectionParam = fn(Traversable&Countable $param) : int => (new SomeClass($param))->getValue(); + +/* testIntersectionReturnType */ +$arrowWithIntersectionReturn = fn($param) : \MyFoo&SomeInterface => new SomeClass($param); + +/* testDNFParamType */ +$arrowWithDNFParam = fn((Traversable&Countable)|null $param) : SomeClass => new SomeClass($param) ?? null; + +/* testDNFReturnType */ +$arrowWithDNFReturn = fn($param) : false|(\MyFoo&SomeInterface) => new \MyFoo($param) ?? false; + +/* testDNFParamTypeWithReturnByRef */ +$arrowWithDNFParamReturnByRef = fn &((A&B)|null $param) => $param * 10; + +/* testTernary */ +$fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b'; + +/* testTernaryWithTypes */ +$fn = fn(int|null $a) : array|null => $a ? null : []; + +function matchInArrow($x) { + /* testWithMatchValue */ + $fn = fn($x) => match(true) { + 1, 2, 3, 4, 5 => 'foo', + default => 'bar', + }; +} + +function matchInArrowAndMore($x) { + /* testWithMatchValueAndMore */ + $fn = fn($x) => match(true) { + 1, 2, 3, 4, 5 => 'foo', + default => 'bar', + } . 'suffix'; +} + +function arrowFunctionInMatchWithTrailingComma($x) { + return match ($x) { + /* testInMatchNotLastValue */ + 1 => fn($y) => callMe($y), + /* testInMatchLastValueWithTrailingComma */ + default => fn($y) => callThem($y), + }; +} + +function arrowFunctionInMatchNoTrailingComma1($x) { + return match ($x) { + 1 => fn($y) => callMe($y), + /* testInMatchLastValueNoTrailingComma1 */ + default => fn($y) => callThem($y) + }; +} + +function arrowFunctionInMatchNoTrailingComma2($x) { + return match ($x) { + /* testInMatchLastValueNoTrailingComma2 */ + default => fn($y) => 5 * $y + }; +} + +/* testConstantDeclaration */ +const FN = 'a'; + +/* testConstantDeclarationLower */ +const fn = 'a'; + +class Foo { + /* testStaticMethodName */ + public static function fn($param) { + /* testNestedInMethod */ + $fn = fn($c) => $callable($factory($c), $c); + } + + public function foo() { + /* testPropertyAssignment */ + $this->fn = 'a'; + } +} + +$anon = new class() { + /* testAnonClassMethodName */ + protected function fN($param) { + } +} + +/* testNonArrowStaticMethodCall */ +$a = Foo::fn($param); + +/* testNonArrowConstantAccess */ +$a = MyClass::FN; + +/* testNonArrowConstantAccessMixed */ +$a = MyClass::Fn; + +/* testNonArrowObjectMethodCall */ +$a = $obj->fn($param); + +/* testNonArrowObjectMethodCallUpper */ +$a = $obj->FN($param); + +/* testNonArrowNamespacedFunctionCall */ +$a = MyNS\Sub\Fn($param); + +/* testNonArrowNamespaceOperatorFunctionCall */ +$a = namespace\fn($param); + +/* testNonArrowFunctionNameWithUnionTypes */ +function fn(int|float $param) : string|null {} + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.php new file mode 100644 index 00000000..e265650f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.php @@ -0,0 +1,967 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillFnTokenTest extends AbstractTokenizerTestCase +{ + + + /** + * Test simple arrow functions. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataSimple + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testSimple($testMarker) + { + $token = $this->getTargetToken($testMarker, T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 12); + + }//end testSimple() + + + /** + * Data provider. + * + * @see testSimple() + * + * @return array> + */ + public static function dataSimple() + { + return [ + 'standard' => [ + 'testMarker' => '/* testStandard */', + ], + 'mixed case' => [ + 'testMarker' => '/* testMixedCase */', + ], + ]; + + }//end dataSimple() + + + /** + * Test whitespace inside arrow function definitions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testWhitespace() + { + $token = $this->getTargetToken('/* testWhitespace */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 6, 13); + + }//end testWhitespace() + + + /** + * Test comments inside arrow function definitions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testComment() + { + $token = $this->getTargetToken('/* testComment */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 8, 15); + + }//end testComment() + + + /** + * Test heredocs inside arrow function definitions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testHeredoc() + { + $token = $this->getTargetToken('/* testHeredoc */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 4, 9); + + }//end testHeredoc() + + + /** + * Test nested arrow functions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNestedOuter() + { + $token = $this->getTargetToken('/* testNestedOuter */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 25); + + }//end testNestedOuter() + + + /** + * Test nested arrow functions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNestedInner() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testNestedInner */', T_FN); + $this->backfillHelper($token, true); + + $expectedScopeOpener = ($token + 5); + $expectedScopeCloser = ($token + 16); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer is not the semicolon token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer is not the semicolon token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame(($token - 4), $tokens[$closer]['scope_opener'], 'Closer scope opener is not the arrow token of the "outer" arrow function (shared scope closer)'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer is not the semicolon token'); + + }//end testNestedInner() + + + /** + * Test nested arrow functions with a shared closer. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNestedSharedCloser() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testNestedSharedCloserOuter */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 4, 20); + + $token = $this->getTargetToken('/* testNestedSharedCloserInner */', T_FN); + $this->backfillHelper($token, true); + + $expectedScopeOpener = ($token + 4); + $expectedScopeCloser = ($token + 12); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for "inner" arrow function is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for "inner" arrow function is not the TRUE token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for "inner" arrow function is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for "inner" arrow function is not the semicolon token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame(($token - 4), $tokens[$closer]['scope_opener'], 'Closer scope opener for "inner" arrow function is not the arrow token of the "outer" arrow function (shared scope closer)'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for "inner" arrow function is not the TRUE token'); + + }//end testNestedSharedCloser() + + + /** + * Test arrow functions that call functions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testFunctionCall() + { + $token = $this->getTargetToken('/* testFunctionCall */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 17); + + }//end testFunctionCall() + + + /** + * Test arrow functions that are included in chained calls. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testChainedFunctionCall() + { + $token = $this->getTargetToken('/* testChainedFunctionCall */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 12, 'bracket'); + + }//end testChainedFunctionCall() + + + /** + * Test arrow functions that are used as function arguments. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testFunctionArgument() + { + $token = $this->getTargetToken('/* testFunctionArgument */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 8, 15, 'comma'); + + }//end testFunctionArgument() + + + /** + * Test arrow functions that use closures. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testClosure() + { + $token = $this->getTargetToken('/* testClosure */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 60, 'comma'); + + }//end testClosure() + + + /** + * Test arrow functions using an array index. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testArrayIndex() + { + $token = $this->getTargetToken('/* testArrayIndex */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 8, 17, 'comma'); + + }//end testArrayIndex() + + + /** + * Test arrow functions with a return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testReturnType() + { + $token = $this->getTargetToken('/* testReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18, 'comma'); + + }//end testReturnType() + + + /** + * Test arrow functions that return a reference. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testReference() + { + $token = $this->getTargetToken('/* testReference */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 6, 9); + + }//end testReference() + + + /** + * Test arrow functions that are grouped by parenthesis. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testGrouped() + { + $token = $this->getTargetToken('/* testGrouped */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 8); + + }//end testGrouped() + + + /** + * Test arrow functions that are used as array values. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testArrayValue() + { + $token = $this->getTargetToken('/* testArrayValue */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 4, 9, 'comma'); + + }//end testArrayValue() + + + /** + * Test arrow functions that are used as array values with no trailing comma. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testArrayValueNoTrailingComma() + { + $token = $this->getTargetToken('/* testArrayValueNoTrailingComma */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 4, 8, 'closing parenthesis'); + + }//end testArrayValueNoTrailingComma() + + + /** + * Test arrow functions that use the yield keyword. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testYield() + { + $token = $this->getTargetToken('/* testYield */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 14); + + }//end testYield() + + + /** + * Test arrow functions that use nullable type with unqualified class name. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNullableUnqualifiedClassName() + { + $token = $this->getTargetToken('/* testNullableUnqualifiedClassName */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 15, 18); + + }//end testNullableUnqualifiedClassName() + + + /** + * Test arrow functions that use namespace relative class name in the return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNamespaceRelativeClassNameInTypes() + { + $token = $this->getTargetToken('/* testNamespaceRelativeClassNameInTypes */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 16, 19); + + }//end testNamespaceRelativeClassNameInTypes() + + + /** + * Test arrow functions that use keyword return types. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataKeywordReturnTypes + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testKeywordReturnTypes($testMarker) + { + $token = $this->getTargetToken($testMarker, T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 14); + + }//end testKeywordReturnTypes() + + + /** + * Data provider. + * + * @see testKeywordReturnTypes() + * + * @return array> + */ + public static function dataKeywordReturnTypes() + { + return [ + 'self' => [ + 'testMarker' => '/* testSelfReturnType */', + ], + 'parent' => [ + 'testMarker' => '/* testParentReturnType */', + ], + 'callable' => [ + 'testMarker' => '/* testCallableReturnType */', + ], + 'array' => [ + 'testMarker' => '/* testArrayReturnType */', + ], + 'static' => [ + 'testMarker' => '/* testStaticReturnType */', + ], + 'false' => [ + 'testMarker' => '/* testFalseReturnType */', + ], + 'true' => [ + 'testMarker' => '/* testTrueReturnType */', + ], + 'null' => [ + 'testMarker' => '/* testNullReturnType */', + ], + ]; + + }//end dataKeywordReturnTypes() + + + /** + * Test arrow function with a union parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionParamType() + { + $token = $this->getTargetToken('/* testUnionParamType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 13, 21); + + }//end testUnionParamType() + + + /** + * Test arrow function with a union return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionReturnType() + { + $token = $this->getTargetToken('/* testUnionReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18); + + }//end testUnionReturnType() + + + /** + * Test arrow function with a union return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionReturnTypeWithTrue() + { + $token = $this->getTargetToken('/* testUnionReturnTypeWithTrue */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18); + + }//end testUnionReturnTypeWithTrue() + + + /** + * Test arrow function with a union return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionReturnTypeWithFalse() + { + $token = $this->getTargetToken('/* testUnionReturnTypeWithFalse */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18); + + }//end testUnionReturnTypeWithFalse() + + + /** + * Test arrow function with an intersection parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testIntersectionParamType() + { + $token = $this->getTargetToken('/* testIntersectionParamType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 13, 27); + + }//end testIntersectionParamType() + + + /** + * Test arrow function with an intersection return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testIntersectionReturnType() + { + $token = $this->getTargetToken('/* testIntersectionReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 12, 20); + + }//end testIntersectionReturnType() + + + /** + * Test arrow function with a DNF parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFParamType() + { + $token = $this->getTargetToken('/* testDNFParamType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 17, 29); + + }//end testDNFParamType() + + + /** + * Test arrow function with a DNF return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFReturnType() + { + $token = $this->getTargetToken('/* testDNFReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 16, 29); + + }//end testDNFReturnType() + + + /** + * Test arrow function which returns by reference with a DNF parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFParamTypeWithReturnByRef() + { + $token = $this->getTargetToken('/* testDNFParamTypeWithReturnByRef */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 15, 22); + + }//end testDNFParamTypeWithReturnByRef() + + + /** + * Test arrow functions used in ternary operators. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTernary() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testTernary */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 40); + + $token = $this->getTargetToken('/* testTernaryThen */', T_FN); + $this->backfillHelper($token); + + $expectedScopeOpener = ($token + 8); + $expectedScopeCloser = ($token + 12); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for THEN is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for THEN is not the semicolon token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for THEN is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for THEN is not the semicolon token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'Closer scope opener for THEN is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for THEN is not the semicolon token'); + + $token = $this->getTargetToken('/* testTernaryElse */', T_FN); + $this->backfillHelper($token, true); + + $expectedScopeOpener = ($token + 8); + $expectedScopeCloser = ($token + 11); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for ELSE is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for ELSE is not the semicolon token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for ELSE is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for ELSE is not the semicolon token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame(($token - 24), $tokens[$closer]['scope_opener'], 'Closer scope opener for ELSE is not the arrow token of the "outer" arrow function (shared scope closer)'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for ELSE is not the semicolon token'); + + }//end testTernary() + + + /** + * Test typed arrow functions used in ternary operators. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTernaryWithTypes() + { + $token = $this->getTargetToken('/* testTernaryWithTypes */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 15, 27); + + }//end testTernaryWithTypes() + + + /** + * Test arrow function returning a match control structure. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testWithMatchValue() + { + $token = $this->getTargetToken('/* testWithMatchValue */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 44); + + }//end testWithMatchValue() + + + /** + * Test arrow function returning a match control structure with something behind it. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testWithMatchValueAndMore() + { + $token = $this->getTargetToken('/* testWithMatchValueAndMore */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 48); + + }//end testWithMatchValueAndMore() + + + /** + * Test match control structure returning arrow functions. + * + * @param string $testMarker The comment prefacing the target token. + * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. + * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. + * @param string $expectedCloserType The type of token expected for the scope closer. + * @param string $expectedCloserFriendlyName A friendly name for the type of token expected for the scope closer + * to be used in the error message for failing tests. + * + * @dataProvider dataInMatchValue + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testInMatchValue($testMarker, $openerOffset, $closerOffset, $expectedCloserType, $expectedCloserFriendlyName) + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, $openerOffset, $closerOffset, $expectedCloserFriendlyName); + + $this->assertSame($expectedCloserType, $tokens[($token + $closerOffset)]['type'], 'Mismatched scope closer type'); + + }//end testInMatchValue() + + + /** + * Data provider. + * + * @see testInMatchValue() + * + * @return array> + */ + public static function dataInMatchValue() + { + return [ + 'not_last_value' => [ + 'testMarker' => '/* testInMatchNotLastValue */', + 'openerOffset' => 5, + 'closerOffset' => 11, + 'expectedCloserType' => 'T_COMMA', + 'expectedCloserFriendlyName' => 'comma', + ], + 'last_value_with_trailing_comma' => [ + 'testMarker' => '/* testInMatchLastValueWithTrailingComma */', + 'openerOffset' => 5, + 'closerOffset' => 11, + 'expectedCloserType' => 'T_COMMA', + 'expectedCloserFriendlyName' => 'comma', + ], + 'last_value_without_trailing_comma_1' => [ + 'testMarker' => '/* testInMatchLastValueNoTrailingComma1 */', + 'openerOffset' => 5, + 'closerOffset' => 10, + 'expectedCloserType' => 'T_CLOSE_PARENTHESIS', + 'expectedCloserFriendlyName' => 'close parenthesis', + ], + 'last_value_without_trailing_comma_2' => [ + 'testMarker' => '/* testInMatchLastValueNoTrailingComma2 */', + 'openerOffset' => 5, + 'closerOffset' => 11, + 'expectedCloserType' => 'T_VARIABLE', + 'expectedCloserFriendlyName' => '$y variable', + ], + ]; + + }//end dataInMatchValue() + + + /** + * Test arrow function nested within a method declaration. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNestedInMethod() + { + $token = $this->getTargetToken('/* testNestedInMethod */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 17); + + }//end testNestedInMethod() + + + /** + * Verify that "fn" keywords which are not arrow functions get tokenized as T_STRING and don't + * have the extra token array indexes. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotAnArrowFunction + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNotAnArrowFunction($testMarker, $testContent='fn') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_STRING, T_FN], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testNotAnArrowFunction() + + + /** + * Data provider. + * + * @see testNotAnArrowFunction() + * + * @return array> + */ + public static function dataNotAnArrowFunction() + { + return [ + 'name of a function, context: declaration' => [ + 'testMarker' => '/* testFunctionName */', + ], + 'name of a constant, context: declaration using "const" keyword - uppercase' => [ + 'testMarker' => '/* testConstantDeclaration */', + 'testContent' => 'FN', + ], + 'name of a constant, context: declaration using "const" keyword - lowercase' => [ + 'testMarker' => '/* testConstantDeclarationLower */', + 'testContent' => 'fn', + ], + 'name of a (static) method, context: declaration' => [ + 'testMarker' => '/* testStaticMethodName */', + ], + 'name of a property, context: property access' => [ + 'testMarker' => '/* testPropertyAssignment */', + ], + 'name of a method, context: declaration in an anon class - mixed case' => [ + 'testMarker' => '/* testAnonClassMethodName */', + 'testContent' => 'fN', + ], + 'name of a method, context: static method call' => [ + 'testMarker' => '/* testNonArrowStaticMethodCall */', + ], + 'name of a constant, context: constant access - uppercase' => [ + 'testMarker' => '/* testNonArrowConstantAccess */', + 'testContent' => 'FN', + ], + 'name of a constant, context: constant access - mixed case' => [ + 'testMarker' => '/* testNonArrowConstantAccessMixed */', + 'testContent' => 'Fn', + ], + 'name of a method, context: method call on object - lowercase' => [ + 'testMarker' => '/* testNonArrowObjectMethodCall */', + ], + 'name of a method, context: method call on object - uppercase' => [ + 'testMarker' => '/* testNonArrowObjectMethodCallUpper */', + 'testContent' => 'FN', + ], + 'name of a (namespaced) function, context: partially qualified function call' => [ + 'testMarker' => '/* testNonArrowNamespacedFunctionCall */', + 'testContent' => 'Fn', + ], + 'name of a (namespaced) function, context: namespace relative function call' => [ + 'testMarker' => '/* testNonArrowNamespaceOperatorFunctionCall */', + ], + 'name of a function, context: declaration with union types for param and return' => [ + 'testMarker' => '/* testNonArrowFunctionNameWithUnionTypes */', + ], + 'unknown - live coding/parse error' => [ + 'testMarker' => '/* testLiveCoding */', + ], + ]; + + }//end dataNotAnArrowFunction() + + + /** + * Helper function to check that all token keys are correctly set for T_FN tokens. + * + * @param int $token The T_FN token to check. + * @param bool $skipScopeCloserCheck Whether to skip the scope closer check. + * This should be set to "true" when testing nested arrow functions, + * where the "inner" arrow function shares a scope closer with the + * "outer" arrow function, as the 'scope_condition' for the scope closer + * of the "inner" arrow function will point to the "outer" arrow function. + * + * @return void + */ + private function backfillHelper($token, $skipScopeCloserCheck=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $this->assertArrayHasKey('scope_condition', $tokens[$token], 'Scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$token], 'Scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$token], 'Scope closer is not set'); + $this->assertSame($tokens[$token]['scope_condition'], $token, 'Scope condition is not the T_FN token'); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$token], 'Parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$token], 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$token], 'Parenthesis closer is not set'); + $this->assertSame($tokens[$token]['parenthesis_owner'], $token, 'Parenthesis owner is not the T_FN token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set'); + $this->assertSame($tokens[$opener]['scope_condition'], $token, 'Opener scope condition is not the T_FN token'); + $this->assertSame(T_FN_ARROW, $tokens[$opener]['code'], 'Arrow scope opener not tokenized as T_FN_ARROW (code)'); + $this->assertSame('T_FN_ARROW', $tokens[$opener]['type'], 'Arrow scope opener not tokenized as T_FN_ARROW (type)'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set'); + if ($skipScopeCloserCheck === false) { + $this->assertSame($tokens[$closer]['scope_condition'], $token, 'Closer scope condition is not the T_FN token'); + } + + $opener = $tokens[$token]['parenthesis_opener']; + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener], 'Opening parenthesis owner is not set'); + $this->assertSame($tokens[$opener]['parenthesis_owner'], $token, 'Opening parenthesis owner is not the T_FN token'); + + $closer = $tokens[$token]['parenthesis_closer']; + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer], 'Closing parenthesis owner is not set'); + $this->assertSame($tokens[$closer]['parenthesis_owner'], $token, 'Closing parenthesis owner is not the T_FN token'); + + }//end backfillHelper() + + + /** + * Helper function to check that the scope opener/closer positions are correctly set for T_FN tokens. + * + * @param int $token The T_FN token to check. + * @param int $openerOffset The expected offset of the scope opener in relation to + * the fn keyword. + * @param int $closerOffset The expected offset of the scope closer in relation to + * the fn keyword. + * @param string $expectedCloserType Optional. The type of token expected for the scope closer. + * + * @return void + */ + private function scopePositionTestHelper($token, $openerOffset, $closerOffset, $expectedCloserType='semicolon') + { + $tokens = $this->phpcsFile->getTokens(); + $expectedScopeOpener = ($token + $openerOffset); + $expectedScopeCloser = ($token + $closerOffset); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer is not the '.$expectedCloserType.' token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer is not the '.$expectedCloserType.' token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'Closer scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer is not the '.$expectedCloserType.' token'); + + }//end scopePositionTestHelper() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.inc new file mode 100644 index 00000000..095a4d7d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.inc @@ -0,0 +1,319 @@ + 'Zero', + 1 => 'One', + 2 => 'Two', + }; +} + +function matchNoTrailingComma($bool) { + /* testMatchNoTrailingComma */ + echo match ($bool) { + true => "true\n", + false => "false\n" + }; +} + +function matchWithDefault($i) { + /* testMatchWithDefault */ + return match ($i) { + 1 => 1, + 2 => 2, + default => 'default', + }; +} + +function matchExpressionInCondition($i) { + /* testMatchExpressionInCondition */ + return match (true) { + $i >= 50 => '50+', + $i >= 40 => '40-50', + $i >= 30 => '30-40', + $i >= 20 => '20-30', + $i >= 10 => '10-20', + default => '0-10', + }; +} + +function matchMultiCase($day) { + /* testMatchMultiCase */ + return match ($day) { + 1, 7 => false, + 2, 3, 4, 5, 6 => true, + }; +} + +function matchMultiCaseTrailingCommaInCase($bool) { + /* testMatchMultiCaseTrailingCommaInCase */ + echo match ($bool) { + false, + 0, + => "false\n", + true, + 1, + => "true\n", + default, + => "not bool\n", + }; +} + +assert((function () { + /* testMatchInClosureNotLowercase */ + Match ('foo') { + 'foo', 'bar' => false, + 'baz' => 'a', + default => 'b', + }; +})()); + +function matchInArrowFunction($x) { + /* testMatchInArrowFunction */ + $fn = fn($x) => match(true) { + 1, 2, 3, 4, 5 => 'foo', + default => 'bar', + }; +} + +function arrowFunctionInMatchNoTrailingComma($x) { + /* testArrowFunctionInMatchNoTrailingComma */ + return match ($x) { + 1 => fn($y) => callMe($y), + default => fn($y) => callThem($y) + }; +} + +/* testMatchInFunctionCallParamNotLowercase */ +var_dump(MATCH ( 'foo' ) { + 'foo' => dump_and_return('foo'), + 'bar' => dump_and_return('bar'), +}); + +/* testMatchInMethodCallParam */ +Test::usesValue(match(true) { true => $i }); + +/* testMatchDiscardResult */ +match (1) { + 1 => print "Executed\n", +}; + +/* testMatchWithDuplicateConditionsWithComments */ +echo match /*comment*/ ( $value /*comment*/ ) { + // Comment. + 2, 1 => '2, 1', + 1 => 1, + 3 => 3, + 4 => 4, + 5 => 5, +}; + +/* testNestedMatchOuter */ +$x = match ($y) { + /* testNestedMatchInner */ + default => match ($z) { 1 => 1 }, +}; + +/* testMatchInTernaryCondition */ +$x = match ($test) { 1 => 'a', 2 => 'b' } ? + /* testMatchInTernaryThen */ match ($test) { 1 => 'a', 2 => 'b' } : + /* testMatchInTernaryElse */ match ($notTest) { 3 => 'a', 4 => 'b' }; + +/* testMatchInArrayValue */ +$array = array( + match ($test) { 1 => 'a', 2 => 'b' }, +); + +/* testMatchInArrayKey */ +$array = [ + match ($test) { 1 => 'a', 2 => 'b' } => 'dynamic keys, woho!', +]; + +/* testMatchreturningArray */ +$matcher = match ($x) { + 0 => array( 0 => 1, 'a' => 2, 'b' => 3 ), + 1 => [1, 2, 3], + 2 => array( 1, [1, 2, 3], 2, 3), + 3 => [ 0 => 1, 'a' => array(1, 2, 3), 'b' => 2, 3], +}; + +/* testSwitchContainingMatch */ +switch ($something) { + /* testMatchWithDefaultNestedInSwitchCase1 */ + case 'foo': + $var = [1, 2, 3]; + $var = match ($i) { + 1 => 1, + default => 'default', + }; + continue 2; + + /* testMatchWithDefaultNestedInSwitchCase2 */ + case 'bar' ; + $i = callMe($a, $b); + return match ($i) { + 1 => 1, + default => 'default', + }; + + /* testMatchWithDefaultNestedInSwitchDefault */ + default: + echo 'something', match ($i) { + 1 => 1, + default => 'default', + }; + break; +} + +/* testMatchContainingSwitch */ +$x = match ($y) { + 5, 8 => function($z) { + /* testSwitchNestedInMatch1 */ + switch($z) { + case 'a': + $var = [1, 2, 3]; + return 'a'; + /* testSwitchDefaultNestedInMatchCase */ + default: + $i = callMe($a, $b); + return 'default1'; + } + }, + default => function($z) { + /* testSwitchNestedInMatch2 */ + switch($z) { + case 'a'; + $i = callMe($a, $b); + return 'b'; + /* testSwitchDefaultNestedInMatchDefault */ + default; + $var = [1, 2, 3]; + return 'default2'; + } + } +}; + +/* testMatchNoCases */ +// Intentional fatal error. +$x = match (true) {}; + +/* testMatchMultiDefault */ +// Intentional fatal error. +echo match (1) { + default => 'foo', + 1 => 'bar', + 2 => 'baz', + default => 'qux', +}; + +/* testNoMatchStaticMethodCall */ +$a = Foo::match($param); + +/* testNoMatchClassConstantAccess */ +$a = MyClass::MATCH; + +/* testNoMatchClassConstantArrayAccessMixedCase */ +$a = MyClass::Match[$a]; + +/* testNoMatchMethodCall */ +$a = $obj->match($param); + +/* testNoMatchMethodCallUpper */ +$a = $obj??->MATCH()->chain($param); + +/* testNoMatchPropertyAccess */ +$a = $obj->match; + +/* testNoMatchNamespacedFunctionCall */ +// Intentional fatal error. +$a = MyNS\Sub\match($param); + +/* testNoMatchNamespaceOperatorFunctionCall */ +// Intentional fatal error. +$a = namespace\match($param); + +interface MatchInterface { + /* testNoMatchInterfaceMethodDeclaration */ + public static function match($param); +} + +class MatchClass { + /* testNoMatchClassConstantDeclarationLower */ + const match = 'a'; + + /* testNoMatchClassMethodDeclaration */ + public static function match($param) { + /* testNoMatchPropertyAssignment */ + $this->match = 'a'; + } +} + +/* testNoMatchClassInstantiation */ +$obj = new Match(); + +$anon = new class() { + /* testNoMatchAnonClassMethodDeclaration */ + protected function maTCH($param) { + } +}; + +/* testNoMatchClassDeclaration */ +// Intentional fatal error. Match is now a reserved keyword. +class Match {} + +/* testNoMatchInterfaceDeclaration */ +// Intentional fatal error. Match is now a reserved keyword. +interface Match {} + +/* testNoMatchTraitDeclaration */ +// Intentional fatal error. Match is now a reserved keyword. +trait Match {} + +/* testNoMatchConstantDeclaration */ +// Intentional fatal error. Match is now a reserved keyword. +const MATCH = '1'; + +/* testNoMatchFunctionDeclaration */ +// Intentional fatal error. Match is now a reserved keyword. +function match() {} + +/* testNoMatchNamespaceDeclaration */ +// Intentional fatal error. Match is now a reserved keyword. +namespace Match {} + +/* testNoMatchExtendedClassDeclaration */ +// Intentional fatal error. Match is now a reserved keyword. +class Foo extends Match {} + +/* testNoMatchImplementedClassDeclaration */ +// Intentional fatal error. Match is now a reserved keyword. +class Bar implements Match {} + +/* testNoMatchInUseStatement */ +// Intentional fatal error in PHP < 8. Match is now a reserved keyword. +use Match\me; + +function brokenMatchNoCurlies($x) { + /* testNoMatchMissingCurlies */ + // Intentional fatal error. New control structure is not supported without curly braces. + return match ($x) + 0 => 'Zero', + 1 => 'One', + 2 => 'Two', + ; +} + +function brokenMatchAlternativeSyntax($x) { + /* testNoMatchAlternativeSyntax */ + // Intentional fatal error. Alternative syntax is not supported. + return match ($x) : + 0 => 'Zero', + 1 => 'One', + 2 => 'Two', + endmatch; +} + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +echo match diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.php new file mode 100644 index 00000000..8214ea1a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.php @@ -0,0 +1,555 @@ + + * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class BackfillMatchTokenTest extends AbstractTokenizerTestCase +{ + + + /** + * Test tokenization of match expressions. + * + * @param string $testMarker The comment prefacing the target token. + * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. + * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. + * @param string $testContent The token content to look for. + * + * @dataProvider dataMatchExpression + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testMatchExpression($testMarker, $openerOffset, $closerOffset, $testContent='match') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_MATCH, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH (code)'); + $this->assertSame('T_MATCH', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH (type)'); + + $this->scopeTestHelper($token, $openerOffset, $closerOffset); + $this->parenthesisTestHelper($token); + + }//end testMatchExpression() + + + /** + * Data provider. + * + * @see testMatchExpression() + * + * @return array> + */ + public static function dataMatchExpression() + { + return [ + 'simple_match' => [ + 'testMarker' => '/* testMatchSimple */', + 'openerOffset' => 6, + 'closerOffset' => 33, + ], + 'no_trailing_comma' => [ + 'testMarker' => '/* testMatchNoTrailingComma */', + 'openerOffset' => 6, + 'closerOffset' => 24, + ], + 'with_default_case' => [ + 'testMarker' => '/* testMatchWithDefault */', + 'openerOffset' => 6, + 'closerOffset' => 33, + ], + 'expression_in_condition' => [ + 'testMarker' => '/* testMatchExpressionInCondition */', + 'openerOffset' => 6, + 'closerOffset' => 77, + ], + 'multicase' => [ + 'testMarker' => '/* testMatchMultiCase */', + 'openerOffset' => 6, + 'closerOffset' => 40, + ], + 'multicase_trailing_comma_in_case' => [ + 'testMarker' => '/* testMatchMultiCaseTrailingCommaInCase */', + 'openerOffset' => 6, + 'closerOffset' => 47, + ], + 'in_closure_not_lowercase' => [ + 'testMarker' => '/* testMatchInClosureNotLowercase */', + 'openerOffset' => 6, + 'closerOffset' => 36, + 'testContent' => 'Match', + ], + 'in_arrow_function' => [ + 'testMarker' => '/* testMatchInArrowFunction */', + 'openerOffset' => 5, + 'closerOffset' => 36, + ], + 'arrow_function_in_match_no_trailing_comma' => [ + 'testMarker' => '/* testArrowFunctionInMatchNoTrailingComma */', + 'openerOffset' => 6, + 'closerOffset' => 44, + ], + 'in_function_call_param_not_lowercase' => [ + 'testMarker' => '/* testMatchInFunctionCallParamNotLowercase */', + 'openerOffset' => 8, + 'closerOffset' => 32, + 'testContent' => 'MATCH', + ], + 'in_method_call_param' => [ + 'testMarker' => '/* testMatchInMethodCallParam */', + 'openerOffset' => 5, + 'closerOffset' => 13, + ], + 'discard_result' => [ + 'testMarker' => '/* testMatchDiscardResult */', + 'openerOffset' => 6, + 'closerOffset' => 18, + ], + 'duplicate_conditions_and_comments' => [ + 'testMarker' => '/* testMatchWithDuplicateConditionsWithComments */', + 'openerOffset' => 12, + 'closerOffset' => 59, + ], + 'nested_match_outer' => [ + 'testMarker' => '/* testNestedMatchOuter */', + 'openerOffset' => 6, + 'closerOffset' => 33, + ], + 'nested_match_inner' => [ + 'testMarker' => '/* testNestedMatchInner */', + 'openerOffset' => 6, + 'closerOffset' => 14, + ], + 'ternary_condition' => [ + 'testMarker' => '/* testMatchInTernaryCondition */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'ternary_then' => [ + 'testMarker' => '/* testMatchInTernaryThen */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'ternary_else' => [ + 'testMarker' => '/* testMatchInTernaryElse */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'array_value' => [ + 'testMarker' => '/* testMatchInArrayValue */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'array_key' => [ + 'testMarker' => '/* testMatchInArrayKey */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'returning_array' => [ + 'testMarker' => '/* testMatchreturningArray */', + 'openerOffset' => 6, + 'closerOffset' => 125, + ], + 'nested_in_switch_case_1' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase1 */', + 'openerOffset' => 6, + 'closerOffset' => 25, + ], + 'nested_in_switch_case_2' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase2 */', + 'openerOffset' => 6, + 'closerOffset' => 25, + ], + 'nested_in_switch_default' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchDefault */', + 'openerOffset' => 6, + 'closerOffset' => 25, + ], + 'match_with_nested_switch' => [ + 'testMarker' => '/* testMatchContainingSwitch */', + 'openerOffset' => 6, + 'closerOffset' => 180, + ], + 'no_cases' => [ + 'testMarker' => '/* testMatchNoCases */', + 'openerOffset' => 6, + 'closerOffset' => 7, + ], + 'multi_default' => [ + 'testMarker' => '/* testMatchMultiDefault */', + 'openerOffset' => 6, + 'closerOffset' => 40, + ], + ]; + + }//end dataMatchExpression() + + + /** + * Verify that "match" keywords which are not match control structures get tokenized as T_STRING + * and don't have the extra token array indexes. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotAMatchStructure + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNotAMatchStructure($testMarker, $testContent='match') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + $next = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($token + 1), null, true); + if ($next !== false && $tokens[$next]['code'] === T_OPEN_PARENTHESIS) { + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set for opener after'); + } + + }//end testNotAMatchStructure() + + + /** + * Data provider. + * + * @see testNotAMatchStructure() + * + * @return array> + */ + public static function dataNotAMatchStructure() + { + return [ + 'static_method_call' => [ + 'testMarker' => '/* testNoMatchStaticMethodCall */', + ], + 'class_constant_access' => [ + 'testMarker' => '/* testNoMatchClassConstantAccess */', + 'testContent' => 'MATCH', + ], + 'class_constant_array_access' => [ + 'testMarker' => '/* testNoMatchClassConstantArrayAccessMixedCase */', + 'testContent' => 'Match', + ], + 'method_call' => [ + 'testMarker' => '/* testNoMatchMethodCall */', + ], + 'method_call_uppercase' => [ + 'testMarker' => '/* testNoMatchMethodCallUpper */', + 'testContent' => 'MATCH', + ], + 'property_access' => [ + 'testMarker' => '/* testNoMatchPropertyAccess */', + ], + 'namespaced_function_call' => [ + 'testMarker' => '/* testNoMatchNamespacedFunctionCall */', + ], + 'namespace_operator_function_call' => [ + 'testMarker' => '/* testNoMatchNamespaceOperatorFunctionCall */', + ], + 'interface_method_declaration' => [ + 'testMarker' => '/* testNoMatchInterfaceMethodDeclaration */', + ], + 'class_constant_declaration' => [ + 'testMarker' => '/* testNoMatchClassConstantDeclarationLower */', + ], + 'class_method_declaration' => [ + 'testMarker' => '/* testNoMatchClassMethodDeclaration */', + ], + 'property_assigment' => [ + 'testMarker' => '/* testNoMatchPropertyAssignment */', + ], + 'class_instantiation' => [ + 'testMarker' => '/* testNoMatchClassInstantiation */', + 'testContent' => 'Match', + ], + 'anon_class_method_declaration' => [ + 'testMarker' => '/* testNoMatchAnonClassMethodDeclaration */', + 'testContent' => 'maTCH', + ], + 'class_declaration' => [ + 'testMarker' => '/* testNoMatchClassDeclaration */', + 'testContent' => 'Match', + ], + 'interface_declaration' => [ + 'testMarker' => '/* testNoMatchInterfaceDeclaration */', + 'testContent' => 'Match', + ], + 'trait_declaration' => [ + 'testMarker' => '/* testNoMatchTraitDeclaration */', + 'testContent' => 'Match', + ], + 'constant_declaration' => [ + 'testMarker' => '/* testNoMatchConstantDeclaration */', + 'testContent' => 'MATCH', + ], + 'function_declaration' => [ + 'testMarker' => '/* testNoMatchFunctionDeclaration */', + ], + 'namespace_declaration' => [ + 'testMarker' => '/* testNoMatchNamespaceDeclaration */', + 'testContent' => 'Match', + ], + 'class_extends_declaration' => [ + 'testMarker' => '/* testNoMatchExtendedClassDeclaration */', + 'testContent' => 'Match', + ], + 'class_implements_declaration' => [ + 'testMarker' => '/* testNoMatchImplementedClassDeclaration */', + 'testContent' => 'Match', + ], + 'use_statement' => [ + 'testMarker' => '/* testNoMatchInUseStatement */', + 'testContent' => 'Match', + ], + 'unsupported_inline_control_structure' => [ + 'testMarker' => '/* testNoMatchMissingCurlies */', + ], + 'unsupported_alternative_syntax' => [ + 'testMarker' => '/* testNoMatchAlternativeSyntax */', + ], + 'live_coding' => [ + 'testMarker' => '/* testLiveCoding */', + ], + ]; + + }//end dataNotAMatchStructure() + + + /** + * Verify that the tokenization of switch structures is not affected by the backfill. + * + * @param string $testMarker The comment prefacing the target token. + * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. + * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. + * + * @dataProvider dataSwitchExpression + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testSwitchExpression($testMarker, $openerOffset, $closerOffset) + { + $token = $this->getTargetToken($testMarker, T_SWITCH); + + $this->scopeTestHelper($token, $openerOffset, $closerOffset); + $this->parenthesisTestHelper($token); + + }//end testSwitchExpression() + + + /** + * Data provider. + * + * @see testSwitchExpression() + * + * @return array> + */ + public static function dataSwitchExpression() + { + return [ + 'switch_containing_match' => [ + 'testMarker' => '/* testSwitchContainingMatch */', + 'openerOffset' => 6, + 'closerOffset' => 174, + ], + 'match_containing_switch_1' => [ + 'testMarker' => '/* testSwitchNestedInMatch1 */', + 'openerOffset' => 5, + 'closerOffset' => 63, + ], + 'match_containing_switch_2' => [ + 'testMarker' => '/* testSwitchNestedInMatch2 */', + 'openerOffset' => 5, + 'closerOffset' => 63, + ], + ]; + + }//end dataSwitchExpression() + + + /** + * Verify that the tokenization of a switch case/default structure containing a match structure + * or contained *in* a match structure is not affected by the backfill. + * + * @param string $testMarker The comment prefacing the target token. + * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. + * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. + * + * @dataProvider dataSwitchCaseVersusMatch + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testSwitchCaseVersusMatch($testMarker, $openerOffset, $closerOffset) + { + $token = $this->getTargetToken($testMarker, [T_CASE, T_DEFAULT]); + + $this->scopeTestHelper($token, $openerOffset, $closerOffset); + + }//end testSwitchCaseVersusMatch() + + + /** + * Data provider. + * + * @see testSwitchCaseVersusMatch() + * + * @return array> + */ + public static function dataSwitchCaseVersusMatch() + { + return [ + 'switch_with_nested_match_case_1' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase1 */', + 'openerOffset' => 3, + 'closerOffset' => 55, + ], + 'switch_with_nested_match_case_2' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase2 */', + 'openerOffset' => 4, + 'closerOffset' => 21, + ], + 'switch_with_nested_match_default_case' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchDefault */', + 'openerOffset' => 1, + 'closerOffset' => 38, + ], + 'match_with_nested_switch_case' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'openerOffset' => 1, + 'closerOffset' => 18, + ], + 'match_with_nested_switch_default_case' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'openerOffset' => 1, + 'closerOffset' => 20, + ], + ]; + + }//end dataSwitchCaseVersusMatch() + + + /** + * Helper function to verify that all scope related array indexes for a control structure + * are set correctly. + * + * @param int $token The control structure token to check. + * @param int $openerOffset The expected offset of the scope opener in relation to + * the control structure token. + * @param int $closerOffset The expected offset of the scope closer in relation to + * the control structure token. + * @param bool $skipScopeCloserCheck Whether to skip the scope closer check. + * This should be set to "true" when testing nested arrow functions, + * where the "inner" arrow function shares a scope closer with the + * "outer" arrow function, as the 'scope_condition' for the scope closer + * of the "inner" arrow function will point to the "outer" arrow function. + * + * @return void + */ + private function scopeTestHelper($token, $openerOffset, $closerOffset, $skipScopeCloserCheck=false) + { + $tokens = $this->phpcsFile->getTokens(); + $tokenArray = $tokens[$token]; + $tokenType = $tokenArray['type']; + $expectedScopeOpener = ($token + $openerOffset); + $expectedScopeCloser = ($token + $closerOffset); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); + $this->assertSame($token, $tokenArray['scope_condition'], 'Scope condition is not the '.$tokenType.' token'); + $this->assertSame($expectedScopeOpener, $tokenArray['scope_opener'], 'Scope opener of the '.$tokenType.' token incorrect'); + $this->assertSame($expectedScopeCloser, $tokenArray['scope_closer'], 'Scope closer of the '.$tokenType.' token incorrect'); + + $opener = $tokenArray['scope_opener']; + $this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set'); + $this->assertSame($token, $tokens[$opener]['scope_condition'], 'Opener scope condition is not the '.$tokenType.' token'); + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], $tokenType.' opener scope opener token incorrect'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], $tokenType.' opener scope closer token incorrect'); + + $closer = $tokenArray['scope_closer']; + $this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set'); + if ($skipScopeCloserCheck === false) { + $this->assertSame($token, $tokens[$closer]['scope_condition'], 'Closer scope condition is not the '.$tokenType.' token'); + } + + $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], $tokenType.' closer scope opener token incorrect'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], $tokenType.' closer scope closer token incorrect'); + + if (($opener + 1) !== $closer) { + for ($i = ($opener + 1); $i < $closer; $i++) { + $this->assertArrayHasKey( + $token, + $tokens[$i]['conditions'], + $tokenType.' condition not added for token belonging to the '.$tokenType.' structure' + ); + } + } + + }//end scopeTestHelper() + + + /** + * Helper function to verify that all parenthesis related array indexes for a control structure + * token are set correctly. + * + * @param int $token The position of the control structure token. + * + * @return void + */ + private function parenthesisTestHelper($token) + { + $tokens = $this->phpcsFile->getTokens(); + $tokenArray = $tokens[$token]; + $tokenType = $tokenArray['type']; + + $this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set'); + $this->assertSame($token, $tokenArray['parenthesis_owner'], 'Parenthesis owner is not the '.$tokenType.' token'); + + $opener = $tokenArray['parenthesis_opener']; + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener], 'Opening parenthesis owner is not set'); + $this->assertSame($token, $tokens[$opener]['parenthesis_owner'], 'Opening parenthesis owner is not the '.$tokenType.' token'); + + $closer = $tokenArray['parenthesis_closer']; + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer], 'Closing parenthesis owner is not set'); + $this->assertSame($token, $tokens[$closer]['parenthesis_owner'], 'Closing parenthesis owner is not the '.$tokenType.' token'); + + }//end parenthesisTestHelper() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.inc new file mode 100644 index 00000000..d8559705 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.inc @@ -0,0 +1,94 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class BackfillNumericSeparatorTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that numbers using numeric separators are tokenized correctly. + * + * @param string $marker The comment which prefaces the target token in the test file. + * @param string $type The expected token type. + * @param string $value The expected token content. + * + * @dataProvider dataTestBackfill + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testBackfill($marker, $type, $value) + { + $tokens = $this->phpcsFile->getTokens(); + $number = $this->getTargetToken($marker, [T_LNUMBER, T_DNUMBER]); + $tokenArray = $tokens[$number]; + + $this->assertSame(constant($type), $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not '.$type.' (code)'); + $this->assertSame($type, $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not '.$type.' (type)'); + $this->assertSame($value, $tokenArray['content']); + + }//end testBackfill() + + + /** + * Data provider. + * + * @see testBackfill() + * + * @return array> + */ + public static function dataTestBackfill() + { + $testHexType = 'T_LNUMBER'; + if (PHP_INT_MAX < 0xCAFEF00D) { + $testHexType = 'T_DNUMBER'; + } + + $testHexMultipleType = 'T_LNUMBER'; + if (PHP_INT_MAX < 0x42726F776E) { + $testHexMultipleType = 'T_DNUMBER'; + } + + $testIntMoreThanMaxType = 'T_LNUMBER'; + if (PHP_INT_MAX < 10223372036854775807) { + $testIntMoreThanMaxType = 'T_DNUMBER'; + } + + return [ + 'decimal integer' => [ + 'marker' => '/* testSimpleLNumber */', + 'type' => 'T_LNUMBER', + 'value' => '1_000_000_000', + ], + 'float' => [ + 'marker' => '/* testSimpleDNumber */', + 'type' => 'T_DNUMBER', + 'value' => '107_925_284.88', + ], + 'float, scientific notation, negative exponent with sigh' => [ + 'marker' => '/* testFloat */', + 'type' => 'T_DNUMBER', + 'value' => '6.674_083e-11', + ], + 'float, scientific notation, positive exponent with sign' => [ + 'marker' => '/* testFloat2 */', + 'type' => 'T_DNUMBER', + 'value' => '6.674_083e+11', + ], + 'float, scientific notation, positive exponent without sign' => [ + 'marker' => '/* testFloat3 */', + 'type' => 'T_DNUMBER', + 'value' => '1_2.3_4e1_23', + ], + 'hexidecimal integer/float' => [ + 'marker' => '/* testHex */', + 'type' => $testHexType, + 'value' => '0xCAFE_F00D', + ], + 'hexidecimal integer/float with multiple underscores' => [ + 'marker' => '/* testHexMultiple */', + 'type' => $testHexMultipleType, + 'value' => '0x42_72_6F_77_6E', + ], + 'hexidecimal integer' => [ + 'marker' => '/* testHexInt */', + 'type' => 'T_LNUMBER', + 'value' => '0x42_72_6F', + ], + 'binary integer' => [ + 'marker' => '/* testBinary */', + 'type' => 'T_LNUMBER', + 'value' => '0b0101_1111', + ], + 'octal integer' => [ + 'marker' => '/* testOctal */', + 'type' => 'T_LNUMBER', + 'value' => '0137_041', + ], + 'octal integer using explicit octal notation' => [ + 'marker' => '/* testExplicitOctal */', + 'type' => 'T_LNUMBER', + 'value' => '0o137_041', + ], + 'octal integer using explicit octal notation with capital O' => [ + 'marker' => '/* testExplicitOctalCapitalised */', + 'type' => 'T_LNUMBER', + 'value' => '0O137_041', + ], + 'integer more than PHP_INT_MAX becomes a float' => [ + 'marker' => '/* testIntMoreThanMax */', + 'type' => $testIntMoreThanMaxType, + 'value' => '10_223_372_036_854_775_807', + ], + ]; + + }//end dataTestBackfill() + + + /** + * Test that numbers using numeric separators which are considered parse errors and/or + * which aren't relevant to the backfill, do not incorrectly trigger the backfill anyway. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array> $expectedTokens The token type and content of the expected token sequence. + * + * @dataProvider dataNoBackfill + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNoBackfill($testMarker, $expectedTokens) + { + $tokens = $this->phpcsFile->getTokens(); + $number = $this->getTargetToken($testMarker, [T_LNUMBER, T_DNUMBER]); + + foreach ($expectedTokens as $key => $expectedToken) { + $i = ($number + $key); + $this->assertSame( + $expectedToken['code'], + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.Tokens::tokenName($expectedToken['code']) + ); + $this->assertSame($expectedToken['content'], $tokens[$i]['content']); + } + + }//end testNoBackfill() + + + /** + * Data provider. + * + * @see testBackfill() + * + * @return array>>> + */ + public static function dataNoBackfill() + { + return [ + 'invalid: trailing underscore' => [ + 'testMarker' => '/* testInvalid1 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '100', + ], + [ + 'code' => T_STRING, + 'content' => '_', + ], + ], + ], + 'invalid: two consecutive underscores' => [ + 'testMarker' => '/* testInvalid2 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '1', + ], + [ + 'code' => T_STRING, + 'content' => '__1', + ], + ], + ], + 'invalid: underscore directly before decimal point' => [ + 'testMarker' => '/* testInvalid3 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '1', + ], + [ + 'code' => T_STRING, + 'content' => '_', + ], + [ + 'code' => T_DNUMBER, + 'content' => '.0', + ], + ], + ], + 'invalid: underscore directly after decimal point' => [ + 'testMarker' => '/* testInvalid4 */', + 'expectedTokens' => [ + [ + 'code' => T_DNUMBER, + 'content' => '1.', + ], + [ + 'code' => T_STRING, + 'content' => '_0', + ], + ], + ], + 'invalid: hex int - underscore directly after x' => [ + 'testMarker' => '/* testInvalid5 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '0', + ], + [ + 'code' => T_STRING, + 'content' => 'x_123', + ], + ], + ], + 'invalid: binary int - underscore directly after b' => [ + 'testMarker' => '/* testInvalid6 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '0', + ], + [ + 'code' => T_STRING, + 'content' => 'b_101', + ], + ], + ], + 'invalid: scientific float - underscore directly before e' => [ + 'testMarker' => '/* testInvalid7 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '1', + ], + [ + 'code' => T_STRING, + 'content' => '_e2', + ], + ], + ], + 'invalid: scientific float - underscore directly after e' => [ + 'testMarker' => '/* testInvalid8 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '1', + ], + [ + 'code' => T_STRING, + 'content' => 'e_2', + ], + ], + ], + 'invalid: space between parts of the number' => [ + 'testMarker' => '/* testInvalid9 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '107_925_284', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_DNUMBER, + 'content' => '.88', + ], + ], + ], + 'invalid: comment within the number' => [ + 'testMarker' => '/* testInvalid10 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '107_925_284', + ], + [ + 'code' => T_COMMENT, + 'content' => '/*comment*/', + ], + [ + 'code' => T_DNUMBER, + 'content' => '.88', + ], + ], + ], + 'invalid: explicit octal int - underscore directly after o' => [ + 'testMarker' => '/* testInvalid11 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '0', + ], + [ + 'code' => T_STRING, + 'content' => 'o_137', + ], + ], + ], + 'invalid: explicit octal int - underscore directly after capital O' => [ + 'testMarker' => '/* testInvalid12 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '0', + ], + [ + 'code' => T_STRING, + 'content' => 'O_41', + ], + ], + ], + 'calculations should be untouched - int - int' => [ + 'testMarker' => '/* testCalc1 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '667_083', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_MINUS, + 'content' => '-', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_LNUMBER, + 'content' => '11', + ], + ], + ], + 'calculations should be untouched - scientific float + int' => [ + 'testMarker' => '/* test Calc2 */', + 'expectedTokens' => [ + [ + 'code' => T_DNUMBER, + 'content' => '6.674_08e3', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_PLUS, + 'content' => '+', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_LNUMBER, + 'content' => '11', + ], + ], + ], + ]; + + }//end dataNoBackfill() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.inc new file mode 100644 index 00000000..eb36e387 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.inc @@ -0,0 +1,156 @@ +readonly = 'foo'; + + /* testReadonlyPropertyInTernaryOperator */ + $isReadonly = $this->readonly ? true : false; + } +} + +/* testReadonlyUsedAsFunctionName */ +function readonly() {} + +/* testReadonlyUsedAsFunctionNameWithReturnByRef */ +function &readonly() {} + +/* testReadonlyUsedAsNamespaceName */ +namespace Readonly; +/* testReadonlyUsedAsPartOfNamespaceName */ +namespace My\Readonly\Collection; +/* testReadonlyAsFunctionCall */ +$var = readonly($a, $b); +/* testReadonlyAsNamespacedFunctionCall */ +$var = My\NS\readonly($a, $b); +/* testReadonlyAsNamespaceRelativeFunctionCall */ +$var = namespace\ReadOnly($a, $b); +/* testReadonlyAsMethodCall */ +$var = $obj->readonly($a, $b); +/* testReadonlyAsNullsafeMethodCall */ +$var = $obj?->readOnly($a, $b); +/* testReadonlyAsStaticMethodCallWithSpace */ +$var = ClassName::readonly ($a, $b); +/* testClassConstantFetchWithReadonlyAsConstantName */ +echo ClassName::READONLY; + +/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */ +$var = readonly /* comment */ (); + +// These test cases are inspired by +// https://github.com/php/php-src/commit/08b75395838b4b42a41e3c70684fa6c6b113eee0 +class ReadonlyWithDisjunctiveNormalForm +{ + /* testReadonlyPropertyDNFTypeUnqualified */ + readonly (B&C)|A $h; + + /* testReadonlyPropertyDNFTypeFullyQualified */ + public readonly (\Fully\Qualified\B&\Full\C)|\Foo\Bar $j; + + /* testReadonlyPropertyDNFTypePartiallyQualified */ + protected readonly (Partially\Qualified&C)|A $l; + + /* testReadonlyPropertyDNFTypeRelativeName */ + private readonly (namespace\Relative&C)|A $n; + + /* testReadonlyPropertyDNFTypeMultipleSets */ + private readonly (A&C)|(B&C)|(C&D) $m; + + /* testReadonlyPropertyDNFTypeWithArray */ + private readonly (B & C)|array $o; + + /* testReadonlyPropertyDNFTypeWithSpacesAndComments */ + private readonly ( B & C /*something*/) | A $q; + + public function __construct( + /* testReadonlyConstructorPropertyPromotionWithDNF */ + private readonly (B&C)|A $b1, + /* testReadonlyConstructorPropertyPromotionWithDNFAndReference */ + readonly (B&C)|A &$b2, + ) {} + + /* testReadonlyUsedAsMethodNameWithDNFParam */ + public function readonly (A&B $param): void {} +} + +/* testReadonlyAnonClassWithParens */ +$anon = new readonly class() {}; + +/* testReadonlyAnonClassWithoutParens */ +$anon = new Readonly class {}; + +/* testReadonlyAnonClassWithCommentsAndWhitespace */ +$anon = new +// comment +READONLY +// phpcs:ignore Stnd.Cat.Sniff +class {}; + +/* testParseErrorLiveCoding */ +// This must be the last test in the file. +readonly diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.php new file mode 100644 index 00000000..89dc3e19 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.php @@ -0,0 +1,271 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillReadonlyTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the "readonly" keyword is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testContent Optional. The token content to look for. + * Defaults to lowercase "readonly". + * + * @dataProvider dataReadonly + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testReadonly($testMarker, $testContent='readonly') + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_READONLY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_READONLY (code)'); + $this->assertSame('T_READONLY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_READONLY (type)'); + + }//end testReadonly() + + + /** + * Data provider. + * + * @see testReadonly() + * + * @return array> + */ + public static function dataReadonly() + { + return [ + 'property declaration, no visibility' => [ + 'testMarker' => '/* testReadonlyProperty */', + ], + 'property declaration, var keyword before' => [ + 'testMarker' => '/* testVarReadonlyProperty */', + ], + 'property declaration, var keyword after' => [ + 'testMarker' => '/* testReadonlyVarProperty */', + ], + 'property declaration, static before' => [ + 'testMarker' => '/* testStaticReadonlyProperty */', + ], + 'property declaration, static after' => [ + 'testMarker' => '/* testReadonlyStaticProperty */', + ], + 'constant declaration, with visibility' => [ + 'testMarker' => '/* testConstReadonlyProperty */', + ], + 'property declaration, missing type' => [ + 'testMarker' => '/* testReadonlyPropertyWithoutType */', + ], + 'property declaration, public before' => [ + 'testMarker' => '/* testPublicReadonlyProperty */', + ], + 'property declaration, protected before' => [ + 'testMarker' => '/* testProtectedReadonlyProperty */', + ], + 'property declaration, private before' => [ + 'testMarker' => '/* testPrivateReadonlyProperty */', + ], + 'property declaration, public after' => [ + 'testMarker' => '/* testPublicReadonlyPropertyWithReadonlyFirst */', + ], + 'property declaration, protected after' => [ + 'testMarker' => '/* testProtectedReadonlyPropertyWithReadonlyFirst */', + ], + 'property declaration, private after' => [ + 'testMarker' => '/* testPrivateReadonlyPropertyWithReadonlyFirst */', + ], + 'property declaration, private before, comments in declaration' => [ + 'testMarker' => '/* testReadonlyWithCommentsInDeclaration */', + ], + 'property declaration, private before, nullable type' => [ + 'testMarker' => '/* testReadonlyWithNullableProperty */', + ], + 'property declaration, private before, union type, null first' => [ + 'testMarker' => '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullFirst */', + ], + 'property declaration, private before, union type, null last' => [ + 'testMarker' => '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullLast */', + ], + 'property declaration, private before, array type' => [ + 'testMarker' => '/* testReadonlyPropertyWithArrayTypeHint */', + ], + 'property declaration, private before, self type' => [ + 'testMarker' => '/* testReadonlyPropertyWithSelfTypeHint */', + ], + 'property declaration, private before, parent type' => [ + 'testMarker' => '/* testReadonlyPropertyWithParentTypeHint */', + ], + 'property declaration, private before, FQN type' => [ + 'testMarker' => '/* testReadonlyPropertyWithFullyQualifiedTypeHint */', + ], + 'property declaration, public before, mixed case' => [ + 'testMarker' => '/* testReadonlyIsCaseInsensitive */', + 'testContent' => 'ReAdOnLy', + ], + 'property declaration, constructor property promotion' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotion */', + ], + 'property declaration, constructor property promotion with reference, mixed case' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotionWithReference */', + 'testContent' => 'ReadOnly', + ], + 'property declaration, in anonymous class' => [ + 'testMarker' => '/* testReadonlyPropertyInAnonymousClass */', + ], + 'property declaration, no visibility, DNF type, unqualified' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeUnqualified */', + ], + 'property declaration, public before, DNF type, fully qualified' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeFullyQualified */', + ], + 'property declaration, protected before, DNF type, partially qualified' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypePartiallyQualified */', + ], + 'property declaration, private before, DNF type, namespace relative name' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeRelativeName */', + ], + 'property declaration, private before, DNF type, multiple sets' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeMultipleSets */', + ], + 'property declaration, private before, DNF type, union with array' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeWithArray */', + ], + 'property declaration, private before, DNF type, with spaces and comment' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeWithSpacesAndComments */', + ], + 'property declaration, constructor property promotion, DNF type' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotionWithDNF */', + ], + 'property declaration, constructor property promotion, DNF type and reference' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotionWithDNFAndReference */', + ], + 'anon class declaration, with parentheses' => [ + 'testMarker' => '/* testReadonlyAnonClassWithParens */', + ], + 'anon class declaration, without parentheses' => [ + 'testMarker' => '/* testReadonlyAnonClassWithoutParens */', + 'testContent' => 'Readonly', + ], + 'anon class declaration, with comments and whitespace' => [ + 'testMarker' => '/* testReadonlyAnonClassWithCommentsAndWhitespace */', + 'testContent' => 'READONLY', + ], + 'live coding / parse error' => [ + 'testMarker' => '/* testParseErrorLiveCoding */', + ], + ]; + + }//end dataReadonly() + + + /** + * Test that "readonly" when not used as the keyword is still tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testContent Optional. The token content to look for. + * Defaults to lowercase "readonly". + * + * @dataProvider dataNotReadonly + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNotReadonly($testMarker, $testContent='readonly') + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotReadonly() + + + /** + * Data provider. + * + * @see testNotReadonly() + * + * @return array> + */ + public static function dataNotReadonly() + { + return [ + 'name of a constant, context: declaration using "const" keyword, uppercase' => [ + 'testMarker' => '/* testReadonlyUsedAsClassConstantName */', + 'testContent' => 'READONLY', + ], + 'name of a method, context: declaration' => [ + 'testMarker' => '/* testReadonlyUsedAsMethodName */', + ], + 'name of a property, context: property access' => [ + 'testMarker' => '/* testReadonlyUsedAsPropertyName */', + ], + 'name of a property, context: property access in ternary' => [ + 'testMarker' => '/* testReadonlyPropertyInTernaryOperator */', + ], + 'name of a function, context: declaration' => [ + 'testMarker' => '/* testReadonlyUsedAsFunctionName */', + ], + 'name of a function, context: declaration with return by ref' => [ + 'testMarker' => '/* testReadonlyUsedAsFunctionNameWithReturnByRef */', + ], + 'name of namespace, context: declaration, mixed case' => [ + 'testMarker' => '/* testReadonlyUsedAsNamespaceName */', + 'testContent' => 'Readonly', + ], + 'partial name of namespace, context: declaration, mixed case' => [ + 'testMarker' => '/* testReadonlyUsedAsPartOfNamespaceName */', + 'testContent' => 'Readonly', + ], + 'name of a function, context: call' => [ + 'testMarker' => '/* testReadonlyAsFunctionCall */', + ], + 'name of a namespaced function, context: partially qualified call' => [ + 'testMarker' => '/* testReadonlyAsNamespacedFunctionCall */', + ], + 'name of a function, context: namespace relative call, mixed case' => [ + 'testMarker' => '/* testReadonlyAsNamespaceRelativeFunctionCall */', + 'testContent' => 'ReadOnly', + ], + 'name of a method, context: method call on object' => [ + 'testMarker' => '/* testReadonlyAsMethodCall */', + ], + 'name of a method, context: nullsafe method call on object' => [ + 'testMarker' => '/* testReadonlyAsNullsafeMethodCall */', + 'testContent' => 'readOnly', + ], + 'name of a method, context: static method call with space after' => [ + 'testMarker' => '/* testReadonlyAsStaticMethodCallWithSpace */', + ], + 'name of a constant, context: constant access - uppercase' => [ + 'testMarker' => '/* testClassConstantFetchWithReadonlyAsConstantName */', + 'testContent' => 'READONLY', + ], + 'name of a function, context: call with space and comment between keyword and parens' => [ + 'testMarker' => '/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */', + ], + 'name of a method, context: declaration with DNF parameter' => [ + 'testMarker' => '/* testReadonlyUsedAsMethodNameWithDNFParam */', + ], + ]; + + }//end dataNotReadonly() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.inc new file mode 100644 index 00000000..822b4413 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.inc @@ -0,0 +1,204 @@ + $param | $int; + +/* testTypeUnionArrowReturnType */ +$arrowWithReturnType = fn ($param) : int|null => $param * 10; + +/* testBitwiseOrInArrayKey */ +$array = array( + A | B => /* testBitwiseOrInArrayValue */ B | C +); + +/* testBitwiseOrInShortArrayKey */ +$array = [ + A | B => /* testBitwiseOrInShortArrayValue */ B | C +]; + +/* testBitwiseOrTryCatch */ +try { +} catch ( ExceptionA | ExceptionB $e ) { +} + +/* testBitwiseOrNonArrowFnFunctionCall */ +$obj->fn($something | $else); + +/* testTypeUnionNonArrowFunctionDeclaration */ +function &fn(int|false $something) {} + +/* testTypeUnionPHP82TrueFirst */ +function trueTypeParam(true|null $param) {} + +/* testTypeUnionPHP82TrueMiddle */ +function trueTypeReturn($param): array|true|null {} + +/* testTypeUnionPHP82TrueLast */ +$closure = function ($param): array|true {} + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +return function( type| diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.php new file mode 100644 index 00000000..bfe409ae --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.php @@ -0,0 +1,167 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BitwiseOrTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that non-union type bitwise or tokens are still tokenized as bitwise or. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataBitwiseOr + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBitwiseOr($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_BITWISE_OR, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_OR (type)'); + + }//end testBitwiseOr() + + + /** + * Data provider. + * + * @see testBitwiseOr() + * + * @return array> + */ + public static function dataBitwiseOr() + { + return [ + 'in simple assignment 1' => ['/* testBitwiseOr1 */'], + 'in simple assignment 2' => ['/* testBitwiseOr2 */'], + 'in OO constant default value' => ['/* testBitwiseOrOOConstDefaultValue */'], + 'in property default value' => ['/* testBitwiseOrPropertyDefaultValue */'], + 'in method parameter default value' => ['/* testBitwiseOrParamDefaultValue */'], + 'in return statement' => ['/* testBitwiseOr3 */'], + 'in closure parameter default value' => ['/* testBitwiseOrClosureParamDefault */'], + 'in OO constant default value DNF-like' => ['/* testBitwiseOrOOConstDefaultValueDNF */'], + 'in property default value DNF-like' => ['/* testBitwiseOrPropertyDefaultValueDNF */'], + 'in method parameter default value DNF-like' => ['/* testBitwiseOrParamDefaultValueDNF */'], + 'in arrow function parameter default value' => ['/* testBitwiseOrArrowParamDefault */'], + 'in arrow function return expression' => ['/* testBitwiseOrArrowExpression */'], + 'in long array key' => ['/* testBitwiseOrInArrayKey */'], + 'in long array value' => ['/* testBitwiseOrInArrayValue */'], + 'in short array key' => ['/* testBitwiseOrInShortArrayKey */'], + 'in short array value' => ['/* testBitwiseOrInShortArrayValue */'], + 'in catch condition' => ['/* testBitwiseOrTryCatch */'], + 'in parameter in function call' => ['/* testBitwiseOrNonArrowFnFunctionCall */'], + 'live coding / undetermined' => ['/* testLiveCoding */'], + ]; + + }//end dataBitwiseOr() + + + /** + * Test that bitwise or tokens when used as part of a union type are tokenized as `T_TYPE_UNION`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataTypeUnion + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTypeUnion($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_TYPE_UNION, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_UNION (code)'); + $this->assertSame('T_TYPE_UNION', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_UNION (type)'); + + }//end testTypeUnion() + + + /** + * Data provider. + * + * @see testTypeUnion() + * + * @return array> + */ + public static function dataTypeUnion() + { + return [ + 'type for OO constant' => ['/* testTypeUnionOOConstSimple */'], + 'type for OO constant, reversed modifier order' => ['/* testTypeUnionOOConstReverseModifierOrder */'], + 'type for OO constant, first of multi-union' => ['/* testTypeUnionOOConstMulti1 */'], + 'type for OO constant, middle of multi-union + comments' => ['/* testTypeUnionOOConstMulti2 */'], + 'type for OO constant, last of multi-union' => ['/* testTypeUnionOOConstMulti3 */'], + 'type for OO constant, using namespace relative names' => ['/* testTypeUnionOOConstNamespaceRelative */'], + 'type for OO constant, using partially qualified names' => ['/* testTypeUnionOOConstPartiallyQualified */'], + 'type for OO constant, using fully qualified names' => ['/* testTypeUnionOOConstFullyQualified */'], + 'type for static property' => ['/* testTypeUnionPropertySimple */'], + 'type for static property, reversed modifier order' => ['/* testTypeUnionPropertyReverseModifierOrder */'], + 'type for property, first of multi-union' => ['/* testTypeUnionPropertyMulti1 */'], + 'type for property, middle of multi-union, also comments' => ['/* testTypeUnionPropertyMulti2 */'], + 'type for property, last of multi-union' => ['/* testTypeUnionPropertyMulti3 */'], + 'type for property using namespace relative names' => ['/* testTypeUnionPropertyNamespaceRelative */'], + 'type for property using partially qualified names' => ['/* testTypeUnionPropertyPartiallyQualified */'], + 'type for property using fully qualified names' => ['/* testTypeUnionPropertyFullyQualified */'], + 'type for readonly property' => ['/* testTypeUnionPropertyWithReadOnlyKeyword */'], + 'type for static readonly property' => ['/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */'], + 'type for readonly property using var keyword' => ['/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */'], + 'type for readonly property, reversed modifier order' => ['/* testTypeUnionPropertyWithReadOnlyKeywordFirst */'], + 'type for readonly property, no visibility' => ['/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */'], + 'type for static property, no visibility' => ['/* testTypeUnionPropertyWithOnlyStaticKeyword */'], + 'type for final property, no visibility' => ['/* testTypeUnionWithPHP84FinalKeyword */'], + 'type for final property, reversed modifier order' => ['/* testTypeUnionWithPHP84FinalKeywordFirst */'], + 'type for final property, no visibility, FQN type' => ['/* testTypeUnionWithPHP84FinalKeywordAndFQN */'], + 'type for private(set) property' => ['/* testTypeUnionPropertyPrivateSet */'], + 'type for public private(set) property' => ['/* testTypeUnionPropertyPublicPrivateSet */'], + 'type for protected(set) property' => ['/* testTypeUnionPropertyProtected */'], + 'type for public protected(set) property' => ['/* testTypeUnionPropertyPublicProtected */'], + 'type for method parameter' => ['/* testTypeUnionParam1 */'], + 'type for method parameter, first in multi-union' => ['/* testTypeUnionParam2 */'], + 'type for method parameter, last in multi-union' => ['/* testTypeUnionParam3 */'], + 'type for method parameter with namespace relative names' => ['/* testTypeUnionParamNamespaceRelative */'], + 'type for method parameter with partially qualified names' => ['/* testTypeUnionParamPartiallyQualified */'], + 'type for method parameter with fully qualified names' => ['/* testTypeUnionParamFullyQualified */'], + 'type for property in constructor property promotion' => ['/* testTypeUnionConstructorPropertyPromotion */'], + 'return type for method' => ['/* testTypeUnionReturnType */'], + 'return type for method, first of multi-union' => ['/* testTypeUnionAbstractMethodReturnType1 */'], + 'return type for method, last of multi-union' => ['/* testTypeUnionAbstractMethodReturnType2 */'], + 'return type for method with namespace relative names' => ['/* testTypeUnionReturnTypeNamespaceRelative */'], + 'return type for method with partially qualified names' => ['/* testTypeUnionReturnPartiallyQualified */'], + 'return type for method with fully qualified names' => ['/* testTypeUnionReturnFullyQualified */'], + 'type for function parameter with reference' => ['/* testTypeUnionWithReference */'], + 'type for function parameter with spread operator' => ['/* testTypeUnionWithSpreadOperator */'], + 'DNF type for OO constant, union before DNF' => ['/* testTypeUnionConstantTypeUnionBeforeDNF */'], + 'DNF type for property, union after DNF' => ['/* testTypeUnionPropertyTypeUnionAfterDNF */'], + 'DNF type for function param, union before and after DNF' => ['/* testTypeUnionParamUnionBeforeAndAfterDNF */'], + 'DNF type for function return, union after DNF with null' => ['/* testTypeUnionReturnTypeUnionAfterDNF */'], + 'type for closure parameter with illegal nullable' => ['/* testTypeUnionClosureParamIllegalNullable */'], + 'return type for closure' => ['/* testTypeUnionClosureReturn */'], + 'type for arrow function parameter' => ['/* testTypeUnionArrowParam */'], + 'return type for arrow function' => ['/* testTypeUnionArrowReturnType */'], + 'type for function parameter, return by ref' => ['/* testTypeUnionNonArrowFunctionDeclaration */'], + 'type for function param with true type first' => ['/* testTypeUnionPHP82TrueFirst */'], + 'return type for function with true type middle' => ['/* testTypeUnionPHP82TrueMiddle */'], + 'return type for closure with true type last' => ['/* testTypeUnionPHP82TrueLast */'], + ]; + + }//end dataTypeUnion() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.inc new file mode 100644 index 00000000..e019dfe8 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.inc @@ -0,0 +1,248 @@ + 'a', + 2 => 'b', + /* testMatchDefaultIsKeyword */ default => 'default', +}; + +$closure = /* testFnIsKeyword */ fn () => 'string'; + +function () { + /* testYieldIsKeyword */ yield $f; + /* testYieldFromIsKeyword */ yield from someFunction(); +}; + +/* testDeclareIsKeyword */ declare(ticks=1): +/* testEndDeclareIsKeyword */ enddeclare; + +if (true /* testAndIsKeyword */ and false /* testOrIsKeyword */ or null /* testXorIsKeyword */ xor 0) { + +} + +$anonymousClass = new /* testAnonymousClassIsKeyword */ class {}; +$anonymousClass2 = new class /* testExtendsInAnonymousClassIsKeyword */ extends SomeParent {}; +$anonymousClass3 = new class /* testImplementsInAnonymousClassIsKeyword */ implements SomeInterface {}; + +$instantiated = new /* testClassInstantiationStaticIsKeyword */ static($param); + +class Foo extends /* testNamespaceInNameIsKeyword */ namespace\Exception +{} + +function /* testKeywordAfterFunctionShouldBeString */ eval() {} +function /* testKeywordAfterFunctionByRefShouldBeString */ &switch() {} + +function /* testKeywordStaticAfterFunctionByRefShouldBeString */ &static() {} + +/* testKeywordAsFunctionCallNameShouldBeStringStatic */ static(); +$obj-> /* testKeywordAsMethodCallNameShouldBeStringStatic */ static(); + +$function = /* testStaticIsKeywordBeforeClosure */ static function(/* testStaticIsKeywordWhenParamType */ static $param) {}; +$arrow = /* testStaticIsKeywordBeforeArrow */ static fn(): /* testStaticIsKeywordWhenReturnType */ static => 10; + +/* testKeywordAsFunctionCallNameShouldBeStringStaticDNFLookaLike */ +$obj->static((CONST_A&CONST_B)|CONST_C | $var); + +class DNF { + public /* testStaticIsKeywordPropertyModifierBeforeDNF */ static (DN&F)|null $dnfProp; +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.php new file mode 100644 index 00000000..09ff9050 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.php @@ -0,0 +1,568 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class ContextSensitiveKeywordsTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that context sensitive keyword is tokenized as string when it should be string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataStrings + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testStrings($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_STRING])); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testStrings() + + + /** + * Data provider. + * + * @see testStrings() + * + * @return array> + */ + public static function dataStrings() + { + return [ + 'constant declaration: abstract' => ['/* testAbstract */'], + 'constant declaration: array' => ['/* testArray */'], + 'constant declaration: as' => ['/* testAs */'], + 'constant declaration: break' => ['/* testBreak */'], + 'constant declaration: callable' => ['/* testCallable */'], + 'constant declaration: case' => ['/* testCase */'], + 'constant declaration: catch' => ['/* testCatch */'], + 'constant declaration: class' => ['/* testClass */'], + 'constant declaration: clone' => ['/* testClone */'], + 'constant declaration: const' => ['/* testConst */'], + 'constant declaration: continue' => ['/* testContinue */'], + 'constant declaration: declare' => ['/* testDeclare */'], + 'constant declaration: default' => ['/* testDefault */'], + 'constant declaration: do' => ['/* testDo */'], + 'constant declaration: echo' => ['/* testEcho */'], + 'constant declaration: else' => ['/* testElse */'], + 'constant declaration: elseif' => ['/* testElseIf */'], + 'constant declaration: empty' => ['/* testEmpty */'], + 'constant declaration: enddeclare' => ['/* testEndDeclare */'], + 'constant declaration: endfor' => ['/* testEndFor */'], + 'constant declaration: endforeach' => ['/* testEndForeach */'], + 'constant declaration: endif' => ['/* testEndIf */'], + 'constant declaration: endswitch' => ['/* testEndSwitch */'], + 'constant declaration: endwhile' => ['/* testEndWhile */'], + 'constant declaration: enum' => ['/* testEnum */'], + 'constant declaration: eval' => ['/* testEval */'], + 'constant declaration: exit' => ['/* testExit */'], + 'constant declaration: extends' => ['/* testExtends */'], + 'constant declaration: final' => ['/* testFinal */'], + 'constant declaration: finally' => ['/* testFinally */'], + 'constant declaration: fn' => ['/* testFn */'], + 'constant declaration: for' => ['/* testFor */'], + 'constant declaration: foreach' => ['/* testForeach */'], + 'constant declaration: function' => ['/* testFunction */'], + 'constant declaration: global' => ['/* testGlobal */'], + 'constant declaration: goto' => ['/* testGoto */'], + 'constant declaration: if' => ['/* testIf */'], + 'constant declaration: implements' => ['/* testImplements */'], + 'constant declaration: include' => ['/* testInclude */'], + 'constant declaration: include_once' => ['/* testIncludeOnce */'], + 'constant declaration: instanceof' => ['/* testInstanceOf */'], + 'constant declaration: insteadof' => ['/* testInsteadOf */'], + 'constant declaration: interface' => ['/* testInterface */'], + 'constant declaration: isset' => ['/* testIsset */'], + 'constant declaration: list' => ['/* testList */'], + 'constant declaration: match' => ['/* testMatch */'], + 'constant declaration: namespace' => ['/* testNamespace */'], + 'constant declaration: new' => ['/* testNew */'], + 'constant declaration: print' => ['/* testPrint */'], + 'constant declaration: private' => ['/* testPrivate */'], + 'constant declaration: protected' => ['/* testProtected */'], + 'constant declaration: public' => ['/* testPublic */'], + 'constant declaration: readonly' => ['/* testReadonly */'], + 'constant declaration: require' => ['/* testRequire */'], + 'constant declaration: require_once' => ['/* testRequireOnce */'], + 'constant declaration: return' => ['/* testReturn */'], + 'constant declaration: static' => ['/* testStatic */'], + 'constant declaration: switch' => ['/* testSwitch */'], + 'constant declaration: throws' => ['/* testThrows */'], + 'constant declaration: trait' => ['/* testTrait */'], + 'constant declaration: try' => ['/* testTry */'], + 'constant declaration: unset' => ['/* testUnset */'], + 'constant declaration: use' => ['/* testUse */'], + 'constant declaration: var' => ['/* testVar */'], + 'constant declaration: while' => ['/* testWhile */'], + 'constant declaration: yield' => ['/* testYield */'], + 'constant declaration: yield_from' => ['/* testYieldFrom */'], + 'constant declaration: and' => ['/* testAnd */'], + 'constant declaration: or' => ['/* testOr */'], + 'constant declaration: xor' => ['/* testXor */'], + + 'constant declaration: array in type' => ['/* testArrayIsTstringInConstType */'], + 'constant declaration: array, name after type' => ['/* testArrayNameForTypedConstant */'], + 'constant declaration: static, name after type' => ['/* testStaticIsNameForTypedConstant */'], + 'constant declaration: private, name after type' => ['/* testPrivateNameForUnionTypedConstant */'], + 'constant declaration: final, name after type' => ['/* testFinalNameForIntersectionTypedConstant */'], + + 'namespace declaration: class' => ['/* testKeywordAfterNamespaceShouldBeString */'], + 'namespace declaration (partial): my' => ['/* testNamespaceNameIsString1 */'], + 'namespace declaration (partial): class' => ['/* testNamespaceNameIsString2 */'], + 'namespace declaration (partial): foreach' => ['/* testNamespaceNameIsString3 */'], + + 'function declaration: eval' => ['/* testKeywordAfterFunctionShouldBeString */'], + 'function declaration with return by ref: switch' => ['/* testKeywordAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: static' => ['/* testKeywordStaticAfterFunctionByRefShouldBeString */'], + + 'function call: static' => ['/* testKeywordAsFunctionCallNameShouldBeStringStatic */'], + 'method call: static' => ['/* testKeywordAsMethodCallNameShouldBeStringStatic */'], + 'method call: static with dnf look a like param' => ['/* testKeywordAsFunctionCallNameShouldBeStringStaticDNFLookaLike */'], + ]; + + }//end dataStrings() + + + /** + * Test that context sensitive keyword is tokenized as keyword when it should be keyword. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedTokenType The expected token type. + * + * @dataProvider dataKeywords + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testKeywords($testMarker, $expectedTokenType) + { + $tokenTargets = Tokens::$contextSensitiveKeywords; + $tokenTargets[] = T_STRING; + $tokenTargets[] = T_ANON_CLASS; + $tokenTargets[] = T_MATCH_DEFAULT; + $tokenTargets[] = T_PRIVATE_SET; + $tokenTargets[] = T_PROTECTED_SET; + $tokenTargets[] = T_PUBLIC_SET; + + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, $tokenTargets); + $tokenArray = $tokens[$target]; + + $this->assertSame( + constant($expectedTokenType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (code)' + ); + $this->assertSame( + $expectedTokenType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (type)' + ); + + }//end testKeywords() + + + /** + * Data provider. + * + * @see testKeywords() + * + * @return array> + */ + public static function dataKeywords() + { + return [ + 'namespace: declaration' => [ + 'testMarker' => '/* testNamespaceIsKeyword */', + 'expectedTokenType' => 'T_NAMESPACE', + ], + 'array: default value in const decl' => [ + 'testMarker' => '/* testArrayIsKeywordInConstDefault */', + 'expectedTokenType' => 'T_ARRAY', + ], + 'static: type in constant declaration' => [ + 'testMarker' => '/* testStaticIsKeywordAsConstType */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: value in constant declaration' => [ + 'testMarker' => '/* testStaticIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_STATIC', + ], + + 'abstract: class declaration' => [ + 'testMarker' => '/* testAbstractIsKeyword */', + 'expectedTokenType' => 'T_ABSTRACT', + ], + 'class: declaration' => [ + 'testMarker' => '/* testClassIsKeyword */', + 'expectedTokenType' => 'T_CLASS', + ], + 'extends: in class declaration' => [ + 'testMarker' => '/* testExtendsIsKeyword */', + 'expectedTokenType' => 'T_EXTENDS', + ], + 'implements: in class declaration' => [ + 'testMarker' => '/* testImplementsIsKeyword */', + 'expectedTokenType' => 'T_IMPLEMENTS', + ], + 'use: in trait import' => [ + 'testMarker' => '/* testUseIsKeyword */', + 'expectedTokenType' => 'T_USE', + ], + 'insteadof: in trait import' => [ + 'testMarker' => '/* testInsteadOfIsKeyword */', + 'expectedTokenType' => 'T_INSTEADOF', + ], + 'as: in trait import' => [ + 'testMarker' => '/* testAsIsKeyword */', + 'expectedTokenType' => 'T_AS', + ], + 'const: declaration' => [ + 'testMarker' => '/* testConstIsKeyword */', + 'expectedTokenType' => 'T_CONST', + ], + 'private: property declaration' => [ + 'testMarker' => '/* testPrivateIsKeyword */', + 'expectedTokenType' => 'T_PRIVATE', + ], + 'protected: property declaration' => [ + 'testMarker' => '/* testProtectedIsKeyword */', + 'expectedTokenType' => 'T_PROTECTED', + ], + 'public: property declaration' => [ + 'testMarker' => '/* testPublicIsKeyword */', + 'expectedTokenType' => 'T_PUBLIC', + ], + 'private(set): property declaration' => [ + 'testMarker' => '/* testPrivateSetIsKeyword */', + 'expectedTokenType' => 'T_PRIVATE_SET', + ], + 'protected(set): property declaration' => [ + 'testMarker' => '/* testProtectedSetIsKeyword */', + 'expectedTokenType' => 'T_PROTECTED_SET', + ], + 'public(set): property declaration' => [ + 'testMarker' => '/* testPublicSetIsKeyword */', + 'expectedTokenType' => 'T_PUBLIC_SET', + ], + 'var: property declaration' => [ + 'testMarker' => '/* testVarIsKeyword */', + 'expectedTokenType' => 'T_VAR', + ], + 'static: property declaration' => [ + 'testMarker' => '/* testStaticIsKeyword */', + 'expectedTokenType' => 'T_STATIC', + ], + 'readonly: property declaration' => [ + 'testMarker' => '/* testReadonlyIsKeywordForProperty */', + 'expectedTokenType' => 'T_READONLY', + ], + 'final: function declaration' => [ + 'testMarker' => '/* testFinalIsKeyword */', + 'expectedTokenType' => 'T_FINAL', + ], + 'function: declaration' => [ + 'testMarker' => '/* testFunctionIsKeyword */', + 'expectedTokenType' => 'T_FUNCTION', + ], + 'callable: param type declaration' => [ + 'testMarker' => '/* testCallableIsKeyword */', + 'expectedTokenType' => 'T_CALLABLE', + ], + 'readonly: anon class declaration' => [ + 'testMarker' => '/* testReadonlyIsKeywordForAnonClass */', + 'expectedTokenType' => 'T_READONLY', + ], + 'return: statement' => [ + 'testMarker' => '/* testReturnIsKeyword */', + 'expectedTokenType' => 'T_RETURN', + ], + + 'interface: declaration' => [ + 'testMarker' => '/* testInterfaceIsKeyword */', + 'expectedTokenType' => 'T_INTERFACE', + ], + 'trait: declaration' => [ + 'testMarker' => '/* testTraitIsKeyword */', + 'expectedTokenType' => 'T_TRAIT', + ], + 'enum: declaration' => [ + 'testMarker' => '/* testEnumIsKeyword */', + 'expectedTokenType' => 'T_ENUM', + ], + + 'new: named instantiation' => [ + 'testMarker' => '/* testNewIsKeyword */', + 'expectedTokenType' => 'T_NEW', + ], + 'instanceof: comparison' => [ + 'testMarker' => '/* testInstanceOfIsKeyword */', + 'expectedTokenType' => 'T_INSTANCEOF', + ], + 'clone' => [ + 'testMarker' => '/* testCloneIsKeyword */', + 'expectedTokenType' => 'T_CLONE', + ], + + 'if' => [ + 'testMarker' => '/* testIfIsKeyword */', + 'expectedTokenType' => 'T_IF', + ], + 'empty' => [ + 'testMarker' => '/* testEmptyIsKeyword */', + 'expectedTokenType' => 'T_EMPTY', + ], + 'elseif' => [ + 'testMarker' => '/* testElseIfIsKeyword */', + 'expectedTokenType' => 'T_ELSEIF', + ], + 'else' => [ + 'testMarker' => '/* testElseIsKeyword */', + 'expectedTokenType' => 'T_ELSE', + ], + 'endif' => [ + 'testMarker' => '/* testEndIfIsKeyword */', + 'expectedTokenType' => 'T_ENDIF', + ], + + 'for' => [ + 'testMarker' => '/* testForIsKeyword */', + 'expectedTokenType' => 'T_FOR', + ], + 'endfor' => [ + 'testMarker' => '/* testEndForIsKeyword */', + 'expectedTokenType' => 'T_ENDFOR', + ], + + 'foreach' => [ + 'testMarker' => '/* testForeachIsKeyword */', + 'expectedTokenType' => 'T_FOREACH', + ], + 'endforeach' => [ + 'testMarker' => '/* testEndForeachIsKeyword */', + 'expectedTokenType' => 'T_ENDFOREACH', + ], + + 'switch' => [ + 'testMarker' => '/* testSwitchIsKeyword */', + 'expectedTokenType' => 'T_SWITCH', + ], + 'case: in switch' => [ + 'testMarker' => '/* testCaseIsKeyword */', + 'expectedTokenType' => 'T_CASE', + ], + 'default: in switch' => [ + 'testMarker' => '/* testDefaultIsKeyword */', + 'expectedTokenType' => 'T_DEFAULT', + ], + 'endswitch' => [ + 'testMarker' => '/* testEndSwitchIsKeyword */', + 'expectedTokenType' => 'T_ENDSWITCH', + ], + 'break: in switch' => [ + 'testMarker' => '/* testBreakIsKeyword */', + 'expectedTokenType' => 'T_BREAK', + ], + 'continue: in switch' => [ + 'testMarker' => '/* testContinueIsKeyword */', + 'expectedTokenType' => 'T_CONTINUE', + ], + + 'do' => [ + 'testMarker' => '/* testDoIsKeyword */', + 'expectedTokenType' => 'T_DO', + ], + 'while' => [ + 'testMarker' => '/* testWhileIsKeyword */', + 'expectedTokenType' => 'T_WHILE', + ], + 'endwhile' => [ + 'testMarker' => '/* testEndWhileIsKeyword */', + 'expectedTokenType' => 'T_ENDWHILE', + ], + + 'try' => [ + 'testMarker' => '/* testTryIsKeyword */', + 'expectedTokenType' => 'T_TRY', + ], + 'throw: statement' => [ + 'testMarker' => '/* testThrowIsKeyword */', + 'expectedTokenType' => 'T_THROW', + ], + 'catch' => [ + 'testMarker' => '/* testCatchIsKeyword */', + 'expectedTokenType' => 'T_CATCH', + ], + 'finally' => [ + 'testMarker' => '/* testFinallyIsKeyword */', + 'expectedTokenType' => 'T_FINALLY', + ], + + 'global' => [ + 'testMarker' => '/* testGlobalIsKeyword */', + 'expectedTokenType' => 'T_GLOBAL', + ], + 'echo' => [ + 'testMarker' => '/* testEchoIsKeyword */', + 'expectedTokenType' => 'T_ECHO', + ], + 'print: statement' => [ + 'testMarker' => '/* testPrintIsKeyword */', + 'expectedTokenType' => 'T_PRINT', + ], + 'die: statement' => [ + 'testMarker' => '/* testDieIsKeyword */', + 'expectedTokenType' => 'T_EXIT', + ], + 'eval' => [ + 'testMarker' => '/* testEvalIsKeyword */', + 'expectedTokenType' => 'T_EVAL', + ], + 'exit: statement' => [ + 'testMarker' => '/* testExitIsKeyword */', + 'expectedTokenType' => 'T_EXIT', + ], + 'isset' => [ + 'testMarker' => '/* testIssetIsKeyword */', + 'expectedTokenType' => 'T_ISSET', + ], + 'unset' => [ + 'testMarker' => '/* testUnsetIsKeyword */', + 'expectedTokenType' => 'T_UNSET', + ], + + 'include' => [ + 'testMarker' => '/* testIncludeIsKeyword */', + 'expectedTokenType' => 'T_INCLUDE', + ], + 'include_once' => [ + 'testMarker' => '/* testIncludeOnceIsKeyword */', + 'expectedTokenType' => 'T_INCLUDE_ONCE', + ], + 'require' => [ + 'testMarker' => '/* testRequireIsKeyword */', + 'expectedTokenType' => 'T_REQUIRE', + ], + 'require_once' => [ + 'testMarker' => '/* testRequireOnceIsKeyword */', + 'expectedTokenType' => 'T_REQUIRE_ONCE', + ], + + 'list' => [ + 'testMarker' => '/* testListIsKeyword */', + 'expectedTokenType' => 'T_LIST', + ], + 'goto' => [ + 'testMarker' => '/* testGotoIsKeyword */', + 'expectedTokenType' => 'T_GOTO', + ], + 'match' => [ + 'testMarker' => '/* testMatchIsKeyword */', + 'expectedTokenType' => 'T_MATCH', + ], + 'default: in match expression' => [ + 'testMarker' => '/* testMatchDefaultIsKeyword */', + 'expectedTokenType' => 'T_MATCH_DEFAULT', + ], + 'fn' => [ + 'testMarker' => '/* testFnIsKeyword */', + 'expectedTokenType' => 'T_FN', + ], + + 'yield' => [ + 'testMarker' => '/* testYieldIsKeyword */', + 'expectedTokenType' => 'T_YIELD', + ], + 'yield from' => [ + 'testMarker' => '/* testYieldFromIsKeyword */', + 'expectedTokenType' => 'T_YIELD_FROM', + ], + + 'declare' => [ + 'testMarker' => '/* testDeclareIsKeyword */', + 'expectedTokenType' => 'T_DECLARE', + ], + 'enddeclare' => [ + 'testMarker' => '/* testEndDeclareIsKeyword */', + 'expectedTokenType' => 'T_ENDDECLARE', + ], + + 'and: in if' => [ + 'testMarker' => '/* testAndIsKeyword */', + 'expectedTokenType' => 'T_LOGICAL_AND', + ], + 'or: in if' => [ + 'testMarker' => '/* testOrIsKeyword */', + 'expectedTokenType' => 'T_LOGICAL_OR', + ], + 'xor: in if' => [ + 'testMarker' => '/* testXorIsKeyword */', + 'expectedTokenType' => 'T_LOGICAL_XOR', + ], + + 'class: anon class declaration' => [ + 'testMarker' => '/* testAnonymousClassIsKeyword */', + 'expectedTokenType' => 'T_ANON_CLASS', + ], + 'extends: anon class declaration' => [ + 'testMarker' => '/* testExtendsInAnonymousClassIsKeyword */', + 'expectedTokenType' => 'T_EXTENDS', + ], + 'implements: anon class declaration' => [ + 'testMarker' => '/* testImplementsInAnonymousClassIsKeyword */', + 'expectedTokenType' => 'T_IMPLEMENTS', + ], + 'static: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationStaticIsKeyword */', + 'expectedTokenType' => 'T_STATIC', + ], + 'namespace: operator' => [ + 'testMarker' => '/* testNamespaceInNameIsKeyword */', + 'expectedTokenType' => 'T_NAMESPACE', + ], + + 'static: closure declaration' => [ + 'testMarker' => '/* testStaticIsKeywordBeforeClosure */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: parameter type (illegal)' => [ + 'testMarker' => '/* testStaticIsKeywordWhenParamType */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: arrow function declaration' => [ + 'testMarker' => '/* testStaticIsKeywordBeforeArrow */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: return type for arrow function' => [ + 'testMarker' => '/* testStaticIsKeywordWhenReturnType */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: property modifier before DNF' => [ + 'testMarker' => '/* testStaticIsKeywordPropertyModifierBeforeDNF */', + 'expectedTokenType' => 'T_STATIC', + ], + ]; + + }//end dataKeywords() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError1Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError1Test.inc new file mode 100644 index 00000000..a6cf511c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError1Test.inc @@ -0,0 +1,17 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class DNFTypesParseError1Test extends AbstractTokenizerTestCase +{ + + + /** + * Document handling for a DNF type / parse error where the last significant type specific token is an open parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeCantEndOnOpenParenthesis + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeCantEndOnOpenParenthesis($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + $token = $tokens[$openPtr]; + + // Verify that the open parenthesis is tokenized as a normal parenthesis. + $this->assertSame(T_OPEN_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (type)'); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + }//end testBrokenDNFTypeCantEndOnOpenParenthesis() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeCantEndOnOpenParenthesis() + * + * @return array> + */ + public static function dataBrokenDNFTypeCantEndOnOpenParenthesis() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeEndOnOpenParenthesis */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeEndOnOpenParenthesis */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeEndOnOpenParenthesis */'], + 'Return type' => ['/* testBrokenReturnDNFTypeEndOnOpenParenthesis */'], + ]; + + }//end dataBrokenDNFTypeCantEndOnOpenParenthesis() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError2Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError2Test.inc new file mode 100644 index 00000000..79297582 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError2Test.inc @@ -0,0 +1,48 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class DNFTypesParseError2Test extends AbstractTokenizerTestCase +{ + + + /** + * Document handling for a DNF type / parse error where the type declaration contains an unmatched parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + // Verify that the unmatched open parenthesis is tokenized as a normal parenthesis. + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + $token = $tokens[$openPtr]; + + $this->assertSame(T_OPEN_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (type)'); + + // Verify that the type intersection is still tokenized as T_BITWISE_AND as the type declaration + // is not recognized as a valid type declaration. + $intersectPtr = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION], '&'); + $token = $tokens[$intersectPtr]; + + $this->assertSame(T_BITWISE_AND, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (type)'); + + }//end testBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + * + * @return array> + */ + public static function dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeParensMissingClose */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeParensMissingClose */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeParensMissingClose */'], + 'Return type' => ['/* testBrokenReturnDNFTypeParensMissingClose */'], + ]; + + }//end dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + + + /** + * Document handling for a DNF type / parse error where the type declaration contains an unmatched parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + // Verify that the unmatched open parenthesis is tokenized as a normal parenthesis. + $closePtr = $this->getTargetToken($testMarker, [T_CLOSE_PARENTHESIS, T_TYPE_CLOSE_PARENTHESIS], ')'); + $token = $tokens[$closePtr]; + + $this->assertSame(T_CLOSE_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_CLOSE_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_CLOSE_PARENTHESIS (type)'); + + // Verify that the type intersection is still tokenized as T_BITWISE_AND as the type declaration + // is not recognized as a valid type declaration. + $intersectPtr = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION], '&'); + $token = $tokens[$intersectPtr]; + + $this->assertSame(T_BITWISE_AND, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (type)'); + + }//end testBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + * + * @return array> + */ + public static function dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeParensMissingOpen */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeParensMissingOpen */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeParensMissingOpen */'], + 'Return type' => ['/* testBrokenReturnDNFTypeParensMissingOpen */'], + ]; + + }//end dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + + + /** + * Document handling for a DNF type / parse error where the type declaration contains an unmatched parenthesis, + * but also contains a set of matched parentheses. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $startPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + + for ($i = $startPtr; $i < $this->phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + if ($tokens[$i]['code'] === T_EQUAL + || $tokens[$i]['code'] === T_VARIABLE + || $tokens[$i]['code'] === T_OPEN_CURLY_BRACKET + ) { + // Reached the end of the type. + break; + } + + $errorPrefix = 'Token tokenized as '.$tokens[$i]['type']; + + // Verify that type tokens have not been retokenized to `T_TYPE_*` tokens for broken type declarations. + switch ($tokens[$i]['content']) { + case '|': + $this->assertSame(T_BITWISE_OR, $tokens[$i]['code'], $errorPrefix.', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $tokens[$i]['type'], $errorPrefix.', not T_BITWISE_OR (type)'); + break; + + case '&': + $this->assertSame(T_BITWISE_AND, $tokens[$i]['code'], $errorPrefix.', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $tokens[$i]['type'], $errorPrefix.', not T_BITWISE_AND (type)'); + break; + + case '(': + // Verify that the open parenthesis is tokenized as a normal parenthesis. + $this->assertSame(T_OPEN_PARENTHESIS, $tokens[$i]['code'], $errorPrefix.', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $tokens[$i]['type'], $errorPrefix.', not T_OPEN_PARENTHESIS (type)'); + break; + + case ')': + $this->assertSame(T_CLOSE_PARENTHESIS, $tokens[$i]['code'], $errorPrefix.', not T_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_CLOSE_PARENTHESIS', $tokens[$i]['type'], $errorPrefix.', not T_CLOSE_PARENTHESIS (type)'); + break; + + default: + break; + }//end switch + }//end for + + }//end testBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + * + * @return array> + */ + public static function dataBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + { + return [ + 'OO const type - missing one close parenthesis' => ['/* testBrokenConstDNFTypeParensMissingOneClose */'], + 'OO property type - missing one open parenthesis' => ['/* testBrokenPropertyDNFTypeParensMissingOneOpen */'], + 'Parameter type - missing one close parenthesis' => ['/* testBrokenParamDNFTypeParensMissingOneClose */'], + 'Return type - missing one open parenthesis' => ['/* testBrokenReturnDNFTypeParensMissingOneOpen */'], + ]; + + }//end dataBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.inc new file mode 100644 index 00000000..ae9dc944 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.inc @@ -0,0 +1,282 @@ + 10 ) {} + +/* testParensOwnerFor */ +for ($i =0; $i < /* testParensNoOwnerInForCondition */ ( CONST_A & CONST_B ); $i++ ); + +/* testParensOwnerMatch */ +$match = match(CONST_A & CONST_B) { + default => $a, +}; + +/* testParensOwnerArray */ +$array = array ( + 'text', + \CONST_A & \Fully\Qualified\CONST_B, + /* testParensNoOwnerFunctionCallWithAmpersandInCallable */ + do_something($a, /* testParensOwnerArrowFn */ fn($b) => $a & $b, $c), +); + +/* testParensOwnerListWithRefVars */ +list(&$a, &$b) = $array; + +/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */ +$obj->static((CONST_A&CONST_B)|CONST_C | $var); + +/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamPlain */ +callMe(label: false); + +/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamUnion */ +callMe(label: CONST_A | CONST_B); + +/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamIntersect */ +callMe(label: CONST_A & CONST_B); + +\Z1\call11( + /* testParensNoOwnerFunctionCallInNamedParam */ + param1: \Z2\call12(), + /* testParensOwnerArrowFunctionInNamedParam */ + param2: fn (): /* testDNFTypeArrowFnReturnInNamedParam */ int|(\Countable&\Iterable) + /* testParensNoOwnerFunctionCallInArrowFnReturn */ + => \Z3\call13(), + /* testParensOwnerClosureInNamedParam */ + param3: function (): /* testDNFTypeClosureReturnInNamedParam */ int|(\DateTime&\ArrayObject) { + /* testParensNoOwnerFunctionCallInClosureReturn */ + return \Z4\call14(); + }, +); + +/* testSwitchControlStructureCondition */ +switch (CONST_A | CONST_B) { + /* testFunctionCallInSwitchCaseCondition */ + case get_bool(): + /* testFunctionCallInSwitchCaseBody */ + \Name\functionInSwitch(); + break; + + default: + /* testFunctionCallInSwitchDefaultBody */ + functionInSwitch(); + break; +} + +/* testIfAlternativeSyntaxCondition */ +if (true): + /* testFunctionCallInIfBody */ + \B\call(); +/* testElseIfAlternativeSyntaxCondition */ +elseif (10): + /* testFunctionCallInElseIfBody */ + C\call(); +else: + /* testFunctionCallInElseBody */ + \C\call3(); +endif; + +gotolabel: + /* testFunctionCallInGotoBody */ + \doSomething(); + +/* testWhileAlternativeSyntaxCondition */ +while ($c3): + /* testFunctionCallInWhileBody */ + \D\call4(); +endwhile; + +/* testForAlternativeSyntaxCondition */ +for ($i = 0; $i < 10; $i++): + /* testFunctionCallInForBody */ + \F\call5(); +endfor; + +/* testForEachAlternativeSyntaxCondition */ +foreach ($array as $key => $value): + /* testFunctionCallInForeachBody */ + \G\call6(); +endforeach; + +/* + * DNF parentheses. + */ + +abstract class DNFTypes { + /* testDNFTypeOOConstUnqualifiedClasses */ + public const (A&B)|D UNQUALIFIED = new Foo; + + /* testDNFTypeOOConstReverseModifierOrder */ + protected final const int|(Foo&Bar)|float MODIFIERS_REVERSED /* testParensNoOwnerOOConstDefaultValue */ = (E_WARNING & E_NOTICE) | E_DEPRECATED; + + const + /* testDNFTypeOOConstMulti1 */ + (A&B) | + /* testDNFTypeOOConstMulti2 */ + (C&D) | // phpcs:ignore Stnd.Cat.Sniff + /* testDNFTypeOOConstMulti3 */ + (Y&D) + | null MULTI_DNF = null; + + /* testDNFTypeOOConstNamespaceRelative */ + final protected const (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC NAMESPACE_RELATIVE = new namespace\Sub\NameB; + + /* testDNFTypeOOConstPartiallyQualified */ + const Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) PARTIALLY_QUALIFIED = new Partially\Qualified\NameA; + + /* testDNFTypeOOConstFullyQualified */ + const (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameC FULLY_QUALIFIED = new \Fully\Qualified\NameB(); + + /* testDNFTypePropertyUnqualifiedClasses */ + public static (Foo&Bar)|array $obj; + + /* testDNFTypePropertyReverseModifierOrder */ + static protected string|(A&B)|int $dnf /* testParensNoOwnerPropertyDefaultValue1 */ = ( E_WARNING & E_NOTICE ) | /* testParensNoOwnerPropertyDefaultValue2 */ (E_ALL & E_DEPRECATED); + + private + /* testDNFTypePropertyMultiNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB) | + /* testDNFTypePropertyMultiPartiallyQualified */ + (Partially\Qualified\NameA&Partially\Qualified\NameB) | // phpcs:ignore Stnd.Cat.Sniff + false + /* testDNFTypePropertyMultiFullyQualified */ + | (\Fully\Qualified\NameA&\Fully\Qualified\NameB) $multiDnf; + + /* testDNFTypePropertyWithReadOnlyKeyword1 */ + protected readonly (A&B) | /* testDNFTypePropertyWithReadOnlyKeyword2 */ (C&D) $readonly; + + /* testDNFTypePropertyWithStaticAndReadOnlyKeywords */ + static readonly (A&B&C)|array $staticReadonly; + + /* testDNFTypePropertyWithOnlyStaticKeyword */ + static (A&B&C)|true $onlyStaticModified; + + /* testDNFTypeWithPHP84FinalKeyword */ + final (className&InterfaceName)|false $finalKeywordA; + + /* testDNFTypeWithPHP84FinalKeywordAndStatic */ + final static (\className&\InterfaceName)|false $finalKeywordB; + + /* testDNFTypePropertyWithPrivateSet */ + private(set) (A&B&C)|true $asym1; + + /* testDNFTypePropertyWithPublicPrivateSet */ + public private(set) (A&B&C)|true $asym2; + + /* testDNFTypePropertyWithProtectedSet */ + protected(set) (A&B&C)|true $asym3; + + /* testDNFTypePropertyWithPublicProtectedSet */ + public protected(set) (A&B&C)|true $asym4; + + public function paramTypes( + /* testDNFTypeParam1WithAttribute */ + #[MyAttribute] + (\Foo&Bar)|int|float $paramA /* testParensNoOwnerParamDefaultValue */ = SOMETHING | (CONSTANT_A & CONSTANT_B), + + /* testDNFTypeParam2 */ + (Foo&\Bar) /* testDNFTypeParam3 */ |(Baz&Fop) &...$paramB, + ) { + /* testParensNoOwnerInReturnValue1 */ + return ( + /* testParensNoOwnerInReturnValue2 */ + ($a1 & $b1) | + /* testParensNoOwnerInReturnValue3 */ + ($a2 & $b2) + ) + $c; + } + + public function identifierNames( + /* testDNFTypeParamNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB)|false $paramA, + /* testDNFTypeParamPartiallyQualified */ + Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) $paramB, + /* testDNFTypeParamFullyQualified */ + name|(\Fully\Qualified\NameA&\Fully\Qualified\NameB) $paramC, + ) {} + + public function __construct( + /* testDNFTypeConstructorPropertyPromotion1 */ + public (A&B)| /* testDNFTypeConstructorPropertyPromotion2 */ (A&D) $property + ) {} + + public function returnType()/* testDNFTypeReturnType1 */ : A|(B&D)|/* testDNFTypeReturnType2 */(B&W)|null {} + + abstract public function abstractMethod(): /* testDNFTypeAbstractMethodReturnType1 */ (X&Y) /* testDNFTypeAbstractMethodReturnType2 */ |(W&Z); + + public function identifierNamesReturnRelative( + ) : /* testDNFTypeReturnTypeNamespaceRelative */ (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC {} + + public function identifierNamesReturnPQ( + ) : /* testDNFTypeReturnPartiallyQualified */Partially\Qualified\NameA|(Partially\Qualified\NameB&Partially\Qualified\NameC) {} + + // Illegal type: segments which are strict subsets of others are disallowed, but that's not the concern of the tokenizer. + public function identifierNamesReturnFQ( + ) /* testDNFTypeReturnFullyQualified */ : (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameB {} +} + +function globalFunctionWithSpreadAndReference( + /* testDNFTypeWithReference */ + float|(B&A) &$paramA, + /* testDNFTypeWithSpreadOperator */ + string|(B&D) ...$paramB +) {} + + +$closureWithParamType = function ( /* testDNFTypeClosureParamIllegalNullable */ ?(A&B)|bool $string) {}; + +/* testParensOwnerClosureAmpersandInDefaultValue */ +$closureWithReturnType = function ($string = NONSENSE & FAKE) /* testDNFTypeClosureReturn */ : (\Package\MyA&PackageB)|null {}; + +$closureWithUseAndReturnType = function ($foo) use ($a) /* testDNFTypeClosureWithUseReturn */ : null|(Foo&\Bar)|false {}; + +/* testParensOwnerArrowDNFUsedWithin */ +$arrowWithParamType = fn ( + /* testDNFTypeArrowParam */ + int|(A&B&C)|array $param, + /* testParensNoOwnerAmpersandInDefaultValue */ ?int $int = (CONSTA & CONSTB )| CONST_C +) + /* testParensNoOwnerInArrowReturnExpression */ + => ($param & $foo ) | $int; + +$arrowWithReturnType = fn ($param) : /* testDNFTypeArrowReturnType */ int|(A&B) => $param * 10; + +$arrowWithParamReturnByRef = fn &( + /* testDNFTypeArrowParamWithReturnByRef */ + (A&B)|null $param +) => $param * 10; + +function InvalidSyntaxes( + /* testDNFTypeParamIllegalUnnecessaryParens */ + (A&B) $parensNotNeeded, + + /* testDNFTypeParamIllegalIntersectUnionReversed */ + A&(B|D) $onlyIntersectAllowedWithinParensAndUnionOutside, + + /* testDNFTypeParamIllegalNestedParens */ + A|(B&(D|W)|null) $nestedParensNotAllowed, +) {} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.php new file mode 100644 index 00000000..5ef220ec --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.php @@ -0,0 +1,550 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class DNFTypesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that parentheses when **not** used in a type declaration are correctly tokenized. + * + * @param string $testMarker The comment prefacing the target token. + * @param bool $skipCheckInside Optional. Skip checking correct token type inside the parentheses. + * Use judiciously for combined normal + DNF tests only. + * + * @dataProvider dataNormalParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNormalParentheses($testMarker, $skipCheckInside=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + $this->assertSame('(', $opener['content'], 'Content of type open parenthesis is not "("'); + $this->assertSame(T_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $opener['type'], 'Token tokenized as '.$opener['type'].', not T_OPEN_PARENTHESIS (type)'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + $this->assertSame(')', $closer['content'], 'Content of type close parenthesis is not ")"'); + $this->assertSame(T_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_CLOSE_PARENTHESIS', $closer['type'], 'Token tokenized as '.$closer['type'].', not T_CLOSE_PARENTHESIS (type)'); + + if ($skipCheckInside === false) { + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + // If there are ampersands, make sure these are tokenized as bitwise and. + if ($tokens[$i]['content'] === '&') { + $this->assertSame(T_BITWISE_AND, $tokens[$i]['code'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_AND (type)'); + } + + // If there are pipes, make sure these are tokenized as bitwise or. + if ($tokens[$i]['content'] === '|') { + $this->assertSame(T_BITWISE_OR, $tokens[$i]['code'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_OR (type)'); + } + } + } + + $before = $this->phpcsFile->findPrevious(Tokens::$emptyTokens, ($openPtr - 1), null, true); + if ($before !== false && $tokens[$before]['content'] === '|') { + $this->assertSame( + T_BITWISE_OR, + $tokens[$before]['code'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_BITWISE_OR (code)' + ); + $this->assertSame( + 'T_BITWISE_OR', + $tokens[$before]['type'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_BITWISE_OR (type)' + ); + } + + $after = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($closePtr + 1), null, true); + if ($after !== false && $tokens[$after]['content'] === '|') { + $this->assertSame( + T_BITWISE_OR, + $tokens[$after]['code'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_BITWISE_OR (code)' + ); + $this->assertSame( + 'T_BITWISE_OR', + $tokens[$after]['type'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_BITWISE_OR (type)' + ); + } + + }//end testNormalParentheses() + + + /** + * Data provider. + * + * @see testNormalParentheses() + * + * @return array> + */ + public static function dataNormalParentheses() + { + // "Owner" offsets are relative to the open parenthesis. + return [ + 'parens without owner' => [ + 'testMarker' => '/* testParensNoOwner */', + ], + 'parens without owner in ternary then' => [ + 'testMarker' => '/* testParensNoOwnerInTernary */', + ], + 'parens without owner in short ternary' => [ + 'testMarker' => '/* testParensNoOwnerInShortTernary */', + ], + 'parens without owner in ternary then (fn call in inline then)' => [ + 'testMarker' => '/* testFnCallParensNoOwnerInTernaryA */', + ], + 'parens without owner in ternary then (fn call in inline else)' => [ + 'testMarker' => '/* testFnCallParensNoOwnerInTernaryB */', + ], + 'parens without owner in short ternary (fn call)' => [ + 'testMarker' => '/* testPFnCallarensNoOwnerInShortTernary */', + ], + 'parens with owner: function; & in default value' => [ + 'testMarker' => '/* testParensOwnerFunctionAmpersandInDefaultValue */', + ], + 'parens with owner: closure; param declared by & ref' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandParamRef */', + ], + 'parens with owner: if' => [ + 'testMarker' => '/* testParensOwnerIf */', + ], + 'parens without owner in if condition' => [ + 'testMarker' => '/* testParensNoOwnerInIfCondition */', + ], + 'parens with owner: for' => [ + 'testMarker' => '/* testParensOwnerFor */', + ], + 'parens without owner in for condition' => [ + 'testMarker' => '/* testParensNoOwnerInForCondition */', + ], + 'parens with owner: match' => [ + 'testMarker' => '/* testParensOwnerMatch */', + ], + 'parens with owner: array' => [ + 'testMarker' => '/* testParensOwnerArray */', + ], + 'parens without owner in array; function call with & in callable' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithAmpersandInCallable */', + ], + 'parens with owner: fn; & in return value' => [ + 'testMarker' => '/* testParensOwnerArrowFn */', + ], + 'parens with owner: list with reference vars' => [ + 'testMarker' => '/* testParensOwnerListWithRefVars */', + ], + 'parens without owner, function call with DNF look-a-like param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */', + ], + 'parens without owner, function call, named param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamPlain */', + ], + 'parens without owner, function call, named param + bitwise or' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamUnion */', + ], + 'parens without owner, function call, named param + bitwise and' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamIntersect */', + ], + 'parens without owner, function call in named param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInNamedParam */', + ], + 'parens with owner: fn; in named param' => [ + 'testMarker' => '/* testParensOwnerArrowFunctionInNamedParam */', + ], + 'parens without owner, function call in named param arrow return' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInArrowFnReturn */', + ], + 'parens with owner: closure; in named param' => [ + 'testMarker' => '/* testParensOwnerClosureInNamedParam */', + ], + 'parens without owner, function call, named param closure return' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInClosureReturn */', + ], + 'parens with owner: switch condition' => [ + 'testMarker' => '/* testSwitchControlStructureCondition */', + ], + 'parens without owner in switch-case condition' => [ + 'testMarker' => '/* testFunctionCallInSwitchCaseCondition */', + ], + 'parens without owner in switch-case body' => [ + 'testMarker' => '/* testFunctionCallInSwitchCaseBody */', + ], + 'parens without owner in switch-default body' => [ + 'testMarker' => '/* testFunctionCallInSwitchDefaultBody */', + ], + 'parens with owner: if condition, alternative syntax' => [ + 'testMarker' => '/* testIfAlternativeSyntaxCondition */', + ], + 'parens without owner in if body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInIfBody */', + ], + 'parens with owner: elseif condition, alternative syntax' => [ + 'testMarker' => '/* testElseIfAlternativeSyntaxCondition */', + ], + 'parens without owner in elseif body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInElseIfBody */', + ], + 'parens without owner in else body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInElseBody */', + ], + 'parens without owner in goto body' => [ + 'testMarker' => '/* testFunctionCallInGotoBody */', + ], + 'parens with owner: while condition, alternative syntax' => [ + 'testMarker' => '/* testWhileAlternativeSyntaxCondition */', + ], + 'parens without owner in while body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInWhileBody */', + ], + 'parens with owner: for condition, alternative syntax' => [ + 'testMarker' => '/* testForAlternativeSyntaxCondition */', + ], + 'parens without owner in for body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInForBody */', + ], + 'parens with owner: foreach condition, alternative syntax' => [ + 'testMarker' => '/* testForEachAlternativeSyntaxCondition */', + ], + 'parens without owner in foreach body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInForeachBody */', + ], + + 'parens without owner in OO const default value' => [ + 'testMarker' => '/* testParensNoOwnerOOConstDefaultValue */', + ], + 'parens without owner in property default 1' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue1 */', + ], + 'parens without owner in property default 2' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue2 */', + ], + 'parens without owner in param default value' => [ + 'testMarker' => '/* testParensNoOwnerParamDefaultValue */', + ], + 'parens without owner in return statement 1' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue1 */', + ], + 'parens without owner in return statement 2' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue2 */', + ], + 'parens without owner in return statement 3' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue3 */', + ], + 'parens with owner: closure; & in default value' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandInDefaultValue */', + ], + 'parens with owner: fn; dnf used within' => [ + 'testMarker' => '/* testParensOwnerArrowDNFUsedWithin */', + 'skipCheckInside' => true, + ], + 'parens without owner: default value for param in arrow function' => [ + 'testMarker' => '/* testParensNoOwnerAmpersandInDefaultValue */', + ], + 'parens without owner in arrow function return expression' => [ + 'testMarker' => '/* testParensNoOwnerInArrowReturnExpression */', + ], + ]; + + }//end dataNormalParentheses() + + + /** + * Test that parentheses when used in a DNF type declaration are correctly tokenized. + * + * Includes verifying that: + * - the tokens between the parentheses all have a "nested_parenthesis" key. + * - all ampersands between the parentheses are tokenized as T_TYPE_INTERSECTION. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataDNFTypeParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFTypeParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + $this->assertSame('(', $opener['content'], 'Content of type open parenthesis is not "("'); + $this->assertSame(T_TYPE_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_TYPE_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_TYPE_OPEN_PARENTHESIS', $opener['type'], 'Token tokenized as '.$opener['type'].', not T_TYPE_OPEN_PARENTHESIS (type)'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + $this->assertSame(')', $closer['content'], 'Content of type close parenthesis is not ")"'); + $this->assertSame(T_TYPE_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_TYPE_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_TYPE_CLOSE_PARENTHESIS', $closer['type'], 'Token tokenized as '.$closer['type'].', not T_TYPE_CLOSE_PARENTHESIS (type)'); + + $intersectionCount = 0; + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + if ($tokens[$i]['content'] === '&') { + $this->assertSame( + T_TYPE_INTERSECTION, + $tokens[$i]['code'], + 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_INTERSECTION (code)' + ); + $this->assertSame( + 'T_TYPE_INTERSECTION', + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_INTERSECTION (type)' + ); + ++$intersectionCount; + } + + // Not valid, but that's irrelevant for the tokenization. + if ($tokens[$i]['content'] === '|') { + $this->assertSame(T_TYPE_UNION, $tokens[$i]['code'], 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_UNION (code)'); + $this->assertSame('T_TYPE_UNION', $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_UNION (type)'); + + // For the purposes of this test, presume it was intended as an intersection. + ++$intersectionCount; + } + }//end for + + $this->assertGreaterThanOrEqual(1, $intersectionCount, 'Did not find an intersection "&" between the DNF type parentheses'); + + $before = $this->phpcsFile->findPrevious(Tokens::$emptyTokens, ($openPtr - 1), null, true); + if ($before !== false && $tokens[$before]['content'] === '|') { + $this->assertSame( + T_TYPE_UNION, + $tokens[$before]['code'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_TYPE_UNION (code)' + ); + $this->assertSame( + 'T_TYPE_UNION', + $tokens[$before]['type'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_TYPE_UNION (type)' + ); + } + + // Invalid, but that's not relevant for the tokenization. + if ($before !== false && $tokens[$before]['content'] === '?') { + $this->assertSame( + T_NULLABLE, + $tokens[$before]['code'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_NULLABLE (code)' + ); + $this->assertSame( + 'T_NULLABLE', + $tokens[$before]['type'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_NULLABLE (type)' + ); + } + + $after = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($closePtr + 1), null, true); + if ($after !== false && $tokens[$after]['content'] === '|') { + $this->assertSame( + T_TYPE_UNION, + $tokens[$after]['code'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_TYPE_UNION (code)' + ); + $this->assertSame( + 'T_TYPE_UNION', + $tokens[$after]['type'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_TYPE_UNION (type)' + ); + } + + }//end testDNFTypeParentheses() + + + /** + * Data provider. + * + * @see testDNFTypeParentheses() + * + * @return array> + */ + public static function dataDNFTypeParentheses() + { + return [ + 'arrow function return type: in named parameter' => [ + 'testMarker' => '/* testDNFTypeArrowFnReturnInNamedParam */', + ], + 'closure return type: in named parameter' => [ + 'testMarker' => '/* testDNFTypeClosureReturnInNamedParam */', + ], + + 'OO const type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstUnqualifiedClasses */', + ], + 'OO const type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypeOOConstReverseModifierOrder */', + ], + 'OO const type: multi-dnf part 1' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti1 */', + ], + 'OO const type: multi-dnf part 2' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti2 */', + ], + 'OO const type: multi-dnf part 3' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti3 */', + ], + 'OO const type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeOOConstNamespaceRelative */', + ], + 'OO const type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstPartiallyQualified */', + ], + 'OO const type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstFullyQualified */', + ], + + 'OO property type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyUnqualifiedClasses */', + ], + 'OO property type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypePropertyReverseModifierOrder */', + ], + 'OO property type: multi-dnf namespace relative classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiNamespaceRelative */', + ], + 'OO property type: multi-dnf partially qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiPartiallyQualified */', + ], + 'OO property type: multi-dnf fully qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiFullyQualified */', + ], + 'OO property type: multi-dnf with readonly keyword 1' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword1 */', + ], + 'OO property type: multi-dnf with readonly keyword 2' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword2 */', + ], + 'OO property type: with static and readonly keywords' => [ + 'testMarker' => '/* testDNFTypePropertyWithStaticAndReadOnlyKeywords */', + ], + 'OO property type: with only static keyword' => [ + 'testMarker' => '/* testDNFTypePropertyWithOnlyStaticKeyword */', + ], + 'OO property type: with only final keyword' => [ + 'testMarker' => '/* testDNFTypeWithPHP84FinalKeyword */', + ], + 'OO property type: with final and static keyword' => [ + 'testMarker' => '/* testDNFTypeWithPHP84FinalKeywordAndStatic */', + ], + 'OO property type: asymmetric visibility, private(set)' => [ + 'testMarker' => '/* testDNFTypePropertyWithPrivateSet */', + ], + 'OO property type: asymmetric vis, public private(set)' => [ + 'testMarker' => '/* testDNFTypePropertyWithPublicPrivateSet */', + ], + 'OO property type: asymmetric visibility, protected(set)' => [ + 'testMarker' => '/* testDNFTypePropertyWithProtectedSet */', + ], + 'OO property type: asymmetric vis, public protected(set)' => [ + 'testMarker' => '/* testDNFTypePropertyWithPublicProtectedSet */', + ], + 'OO method param type: first param' => [ + 'testMarker' => '/* testDNFTypeParam1WithAttribute */', + ], + 'OO method param type: second param, first DNF' => [ + 'testMarker' => '/* testDNFTypeParam2 */', + ], + 'OO method param type: second param, second DNF' => [ + 'testMarker' => '/* testDNFTypeParam3 */', + ], + 'OO method param type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeParamNamespaceRelative */', + ], + 'OO method param type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamPartiallyQualified */', + ], + 'OO method param type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamFullyQualified */', + ], + 'Constructor property promotion with multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion1 */', + ], + 'Constructor property promotion with multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion2 */', + ], + 'OO method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeReturnType1 */', + ], + 'OO method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeReturnType2 */', + ], + 'OO abstract method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType1 */', + ], + 'OO abstract method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType2 */', + ], + 'OO method return type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeReturnTypeNamespaceRelative */', + ], + 'OO method return type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnPartiallyQualified */', + ], + 'OO method return type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnFullyQualified */', + ], + 'function param type: with reference' => [ + 'testMarker' => '/* testDNFTypeWithReference */', + ], + 'function param type: with spread' => [ + 'testMarker' => '/* testDNFTypeWithSpreadOperator */', + ], + 'closure param type: with illegal nullable' => [ + 'testMarker' => '/* testDNFTypeClosureParamIllegalNullable */', + ], + 'closure return type' => [ + 'testMarker' => '/* testDNFTypeClosureReturn */', + ], + 'closure with use return type' => [ + 'testMarker' => '/* testDNFTypeClosureWithUseReturn */', + ], + + 'arrow function param type' => [ + 'testMarker' => '/* testDNFTypeArrowParam */', + ], + 'arrow function return type' => [ + 'testMarker' => '/* testDNFTypeArrowReturnType */', + ], + 'arrow function param type with return by ref' => [ + 'testMarker' => '/* testDNFTypeArrowParamWithReturnByRef */', + ], + + 'illegal syntax: unnecessary parentheses (no union)' => [ + 'testMarker' => '/* testDNFTypeParamIllegalUnnecessaryParens */', + ], + 'illegal syntax: union within parentheses, intersect outside' => [ + 'testMarker' => '/* testDNFTypeParamIllegalIntersectUnionReversed */', + ], + 'illegal syntax: nested parentheses' => [ + 'testMarker' => '/* testDNFTypeParamIllegalNestedParens */', + ], + ]; + + }//end dataDNFTypeParentheses() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.inc new file mode 100644 index 00000000..648149d2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.inc @@ -0,0 +1,203 @@ + 1, + 2 => 2, + /* testSimpleMatchDefault */ + default => 'default', + }; +} + +function switchWithDefault($i) { + switch ($i) { + case 1: + return 1; + case 2: + return 2; + /* testSimpleSwitchDefault */ + default: + return 'default'; + } +} + +function switchWithDefaultAndCurlies($i) { + switch ($i) { + case 1: + return 1; + case 2: + return 2; + /* testSimpleSwitchDefaultWithCurlies */ + default: { + return 'default'; + } + } +} + +function matchWithDefaultInSwitch() { + switch ($something) { + case 'foo': + $var = [1, 2, 3]; + $var = match ($i) { + 1 => 1, + /* testMatchDefaultNestedInSwitchCase1 */ + default => 'default', + }; + continue; + + case 'bar' : + $i = callMe($a, $b); + return match ($i) { + 1 => 1, + /* testMatchDefaultNestedInSwitchCase2 */ + default => 'default', + }; + + /* testSwitchDefault */ + default; + echo 'something', match ($i) { + 1, => 1, + /* testMatchDefaultNestedInSwitchDefault */ + default, => 'default', + }; + break; + } +} + +function switchWithDefaultInMatch() { + $x = match ($y) { + 5, 8 => function($z) { + switch($z) { + case 'a'; + $var = [1, 2, 3]; + return 'a'; + /* testSwitchDefaultNestedInMatchCase */ + default: + $var = [1, 2, 3]; + return 'default1'; + } + }, + /* testMatchDefault */ + default => function($z) { + switch($z) { + case 'a': + $i = callMe($a, $b); + return 'b'; + /* testSwitchDefaultNestedInMatchDefault */ + default: + $i = callMe($a, $b); + return 'default2'; + } + } + }; +} + +function shortArrayWithConstantKey() { + $arr = [ + /* testClassConstantAsShortArrayKey */ + SomeClass::DEFAULT => 1, + /* testClassPropertyAsShortArrayKey */ + SomeClass->DEFAULT => 1, + /* testNamespacedConstantAsShortArrayKey */ + // Intentional parse error PHP < 8.0. Reserved keyword used as namespaced constant. + SomeNamespace\DEFAULT => 1, + /* testFQNGlobalConstantAsShortArrayKey */ + // Intentional parse error in PHP < 8.0. Reserved keyword used as global constant. + \DEFAULT => 1, + ]; +} + +function longArrayWithConstantKey() { + $arr = array( + /* testClassConstantAsLongArrayKey */ + SomeClass::DEFAULT => 1, + ); +} + +function yieldWithConstantKey() { + /* testClassConstantAsYieldKey */ + yield SomeClass::DEFAULT => 1; +} + +function longArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchDefaultWithNestedLongArrayWithClassConstantKey */ + DEFAULT => array( + /* testClassConstantAsLongArrayKeyNestedInMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */ + DEFAULT => array( + /* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */ + SomeClass::DEFAULT => 1, + ), + }, + ), + }; +} + +function shortArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchDefaultWithNestedShortArrayWithClassConstantKey */ + DEFAULT => [ + /* testClassConstantAsShortArrayKeyNestedInMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */ + DEFAULT => [ + /* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */ + SomeClass::DEFAULT => 1, + ], + }, + ], + }; +} + + +function longArrayWithConstantKeyWithNestedMatch() { + return array( + /* testClassConstantAsLongArrayKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultNestedInLongArray */ + DEFAULT => 'foo' + }, + ); +} + +function shortArrayWithConstantKeyWithNestedMatch() { + return [ + /* testClassConstantAsShortArrayKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultNestedInShortArray */ + DEFAULT => 'foo' + }, + ]; +} + +function switchWithConstantNonDefault($i) { + switch ($i) { + /* testClassConstantInSwitchCase */ + case SomeClass::DEFAULT: + return 1; + + /* testClassPropertyInSwitchCase */ + case SomeClass->DEFAULT: + return 2; + + /* testNamespacedConstantInSwitchCase */ + // Intentional parse error PHP < 8.0. Reserved keyword used as constant. + case SomeNamespace\DEFAULT: + return 2; + + /* testNamespaceRelativeConstantInSwitchCase */ + // Intentional parse error PHP < 8.0. Reserved keyword used as global constant. + case namespace\DEFAULT: + return 2; + } +} + +class Foo { + /* testClassConstant */ + const DEFAULT = 'foo'; + + /* testMethodDeclaration */ + public function default() {} +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.php new file mode 100644 index 00000000..c398aa6c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.php @@ -0,0 +1,255 @@ + + * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class DefaultKeywordTest extends AbstractTokenizerTestCase +{ + + + /** + * Test the retokenization of the `default` keyword for match structure to `T_MATCH_DEFAULT`. + * + * Note: Cases and default structures within a match structure do *NOT* get case/default scope + * conditions, in contrast to case and default structures in switch control structures. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataMatchDefault + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testMatchDefault($testMarker, $testContent='default') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_MATCH_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (code)'); + $this->assertSame('T_MATCH_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (type)'); + + }//end testMatchDefault() + + + /** + * Data provider. + * + * @see testMatchDefault() + * + * @return array> + */ + public static function dataMatchDefault() + { + return [ + 'simple_match_default' => [ + 'testMarker' => '/* testSimpleMatchDefault */', + ], + 'match_default_in_switch_case_1' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase1 */', + ], + 'match_default_in_switch_case_2' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase2 */', + ], + 'match_default_in_switch_default' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchDefault */', + ], + 'match_default_containing_switch' => [ + 'testMarker' => '/* testMatchDefault */', + ], + + 'match_default_with_nested_long_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_long_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_long_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInLongArray */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_short_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInShortArray */', + 'testContent' => 'DEFAULT', + ], + ]; + + }//end dataMatchDefault() + + + /** + * Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively + * impact the tokenization of `T_DEFAULT` tokens in switch control structures. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataSwitchDefault + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testSwitchDefault($testMarker, $testContent='default') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (code)'); + $this->assertSame('T_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (type)'); + + }//end testSwitchDefault() + + + /** + * Data provider. + * + * @see testSwitchDefault() + * + * @return array> + */ + public static function dataSwitchDefault() + { + return [ + 'simple_switch_default' => [ + 'testMarker' => '/* testSimpleSwitchDefault */', + ], + 'simple_switch_default_with_curlies' => [ + 'testMarker' => '/* testSimpleSwitchDefaultWithCurlies */', + ], + 'switch_default_toplevel' => [ + 'testMarker' => '/* testSwitchDefault */', + ], + 'switch_default_nested_in_match_case' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', + ], + 'switch_default_nested_in_match_default' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + ], + ]; + + }//end dataSwitchDefault() + + + /** + * Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively + * impact the tokenization of `T_STRING` tokens with the contents 'default' which aren't in + * actual fact the default keyword. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotDefaultKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotDefaultKeyword() + + + /** + * Data provider. + * + * @see testNotDefaultKeyword() + * + * @return array> + */ + public static function dataNotDefaultKeyword() + { + return [ + 'class-constant-as-short-array-key' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKey */', + ], + 'class-property-as-short-array-key' => [ + 'testMarker' => '/* testClassPropertyAsShortArrayKey */', + ], + 'namespaced-constant-as-short-array-key' => [ + 'testMarker' => '/* testNamespacedConstantAsShortArrayKey */', + ], + 'fqn-global-constant-as-short-array-key' => [ + 'testMarker' => '/* testFQNGlobalConstantAsShortArrayKey */', + ], + 'class-constant-as-long-array-key' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKey */', + ], + 'class-constant-as-yield-key' => [ + 'testMarker' => '/* testClassConstantAsYieldKey */', + ], + + 'class-constant-as-long-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatch */', + ], + 'class-constant-as-long-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-short-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatch */', + ], + 'class-constant-as-short-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-long-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyWithNestedMatch */', + ], + 'class-constant-as-short-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyWithNestedMatch */', + ], + + 'class-constant-in-switch-case' => [ + 'testMarker' => '/* testClassConstantInSwitchCase */', + ], + 'class-property-in-switch-case' => [ + 'testMarker' => '/* testClassPropertyInSwitchCase */', + ], + 'namespaced-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespacedConstantInSwitchCase */', + ], + 'namespace-relative-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespaceRelativeConstantInSwitchCase */', + ], + + 'class-constant-declaration' => [ + 'testMarker' => '/* testClassConstant */', + ], + 'class-method-declaration' => [ + 'testMarker' => '/* testMethodDeclaration */', + 'testContent' => 'default', + ], + ]; + + }//end dataNotDefaultKeyword() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.inc new file mode 100644 index 00000000..b67b0660 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.inc @@ -0,0 +1,281 @@ + 'Zero', + ); +} + +function simpleShortArray($x) { + return [ + /* testShortArrayArrowSimple */ + 0 => 'Zero', + ]; +} + +function simpleLongList($x) { + list( + /* testLongListArrowSimple */ + 0 => $a, + ) = $x; +} + +function simpleShortList($x) { + [ + /* testShortListArrowSimple */ + 0 => $a, + ] = $x; +} + +function simpleYield($x) { + $i = 0; + foreach (explode("\n", $x) as $line) { + /* testYieldArrowSimple */ + yield ++$i => $line; + } +} + +function simpleForeach($x) { + /* testForeachArrowSimple */ + foreach ($x as $k => $value) {} +} + +function simpleMatch($x) { + return match ($x) { + /* testMatchArrowSimpleSingleCase */ + 0 => 'Zero', + /* testMatchArrowSimpleMultiCase */ + 2, 4, 6 => 'Zero', + /* testMatchArrowSimpleSingleCaseWithTrailingComma */ + 1, => 'Zero', + /* testMatchArrowSimpleMultiCaseWithTrailingComma */ + 3, 5, => 'Zero', + }; +} + +function simpleArrowFunction($y) { + /* testFnArrowSimple */ + return fn ($y) => callMe($y); +} + +function matchNestedInMatch() { + $x = match ($y) { + /* testMatchArrowNestedMatchOuter */ + default, => match ($z) { + /* testMatchArrowNestedMatchInner */ + 1 => 1 + }, + }; +} + +function matchNestedInLongArrayValue() { + $array = array( + /* testLongArrayArrowWithNestedMatchValue1 */ + 'a' => match ($test) { + /* testMatchArrowInLongArrayValue1 */ + 1 => 'a', + /* testMatchArrowInLongArrayValue2 */ + 2 => 'b' + }, + /* testLongArrayArrowWithNestedMatchValue2 */ + $i => match ($test) { + /* testMatchArrowInLongArrayValue3 */ + 1 => 'a', + }, + ); +} + +function matchNestedInShortArrayValue() { + $array = [ + /* testShortArrayArrowWithNestedMatchValue1 */ + 'a' => match ($test) { + /* testMatchArrowInShortArrayValue1 */ + 1 => 'a', + /* testMatchArrowInShortArrayValue2 */ + 2 => 'b' + }, + /* testShortArrayArrowWithNestedMatchValue2 */ + $i => match ($test) { + /* testMatchArrowInShortArrayValue3 */ + 1 => 'a', + }, + ]; +} + +function matchNestedInLongArrayKey() { + $array = array( + match ($test) { /* testMatchArrowInLongArrayKey1 */ 1 => 'a', /* testMatchArrowInLongArrayKey2 */ 2 => 'b' } + /* testLongArrayArrowWithMatchKey */ + => 'dynamic keys, woho!', + ); +} + +function matchNestedInShortArrayKey() { + $array = [ + match ($test) { /* testMatchArrowInShortArrayKey1 */ 1 => 'a', /* testMatchArrowInShortArrayKey2 */ 2 => 'b' } + /* testShortArrayArrowWithMatchKey */ + => 'dynamic keys, woho!', + ]; +} + +function arraysNestedInMatch() { + $matcher = match ($x) { + /* testMatchArrowWithLongArrayBodyWithKeys */ + 0 => array( + /* testLongArrayArrowInMatchBody1 */ + 0 => 1, + /* testLongArrayArrowInMatchBody2 */ + 'a' => 2, + /* testLongArrayArrowInMatchBody3 */ + 'b' => 3 + ), + /* testMatchArrowWithShortArrayBodyWithoutKeys */ + 1 => [1, 2, 3], + /* testMatchArrowWithLongArrayBodyWithoutKeys */ + 2 => array( 1, [1, 2, 3], 2, 3), + /* testMatchArrowWithShortArrayBodyWithKeys */ + 3 => [ + /* testShortArrayArrowInMatchBody1 */ + 0 => 1, + /* testShortArrayArrowInMatchBody2 */ + 'a' => array(1, 2, 3), + /* testShortArrayArrowInMatchBody3 */ + 'b' => 2, + 3 + ], + /* testShortArrayArrowinMatchCase1 */ + [4 => 'a', /* testShortArrayArrowinMatchCase2 */ 5 => 6] + /* testMatchArrowWithShortArrayWithKeysAsCase */ + => 'match with array as case value', + /* testShortArrayArrowinMatchCase3 */ + [4 => 'a'], /* testLongArrayArrowinMatchCase4 */ array(5 => 6), + /* testMatchArrowWithMultipleArraysWithKeysAsCase */ + => 'match with multiple arrays as case value', + }; +} + +function matchNestedInArrowFunction($x) { + /* testFnArrowWithMatchInValue */ + $fn = fn($x) => match(true) { + /* testMatchArrowInFnBody1 */ + 1, 2, 3, 4, 5 => 'foo', + /* testMatchArrowInFnBody2 */ + default => 'bar', + }; +} + +function arrowFunctionsNestedInMatch($x) { + return match ($x) { + /* testMatchArrowWithFnBody1 */ + 1 => /* testFnArrowInMatchBody1 */ fn($y) => callMe($y), + /* testMatchArrowWithFnBody2 */ + default => /* testFnArrowInMatchBody2 */ fn($y) => callThem($y) + }; +} + +function matchShortArrayMismash() { + $array = [ + match ($test) { + /* testMatchArrowInComplexShortArrayKey1 */ + 1 => [ /* testShortArrayArrowInComplexMatchValueinShortArrayKey */ 1 => 'a'], + /* testMatchArrowInComplexShortArrayKey2 */ + 2 => 'b' + /* testShortArrayArrowInComplexMatchArrayMismash */ + } => match ($test) { + /* testMatchArrowInComplexShortArrayValue1 */ + 1 => [ /* testShortArrayArrowInComplexMatchValueinShortArrayValue */ 1 => 'a'], + /* testMatchArrowInComplexShortArrayValue2 */ + 2 => /* testFnArrowInComplexMatchValueInShortArrayValue */ fn($y) => callMe($y) + }, + ]; +} + + +function longListInMatch($x, $y) { + return match($x) { + /* testMatchArrowWithLongListBody */ + 1 => list('a' => $a, /* testLongListArrowInMatchBody */ 'b' => $b, 'c' => list('d' => $c)) = $y, + /* testLongListArrowInMatchCase */ + list('a' => $a, 'b' => $b) = $y /* testMatchArrowWithLongListInCase */ => 'something' + }; +} + +function shortListInMatch($x, $y) { + return match($x) { + /* testMatchArrowWithShortListBody */ + 1 => ['a' => $a, 'b' => $b, 'c' => /* testShortListArrowInMatchBody */ ['d' => $c]] = $y, + /* testShortListArrowInMatchCase */ + ['a' => $a, 'b' => $b] = $y /* testMatchArrowWithShortListInCase */ => 'something' + }; +} + +function matchInLongList() { + /* testMatchArrowInLongListKey */ + list(match($x) {1 => 1, 2 => 2} /* testLongListArrowWithMatchInKey */ => $a) = $array; +} + +function matchInShortList() { + /* testMatchArrowInShortListKey */ + [match($x) {1 => 1, 2 => 2} /* testShortListArrowWithMatchInKey */ => $a] = $array; +} + +function longArrayWithConstantKey() { + $arr = array( + /* testLongArrayArrowWithClassConstantKey */ + SomeClass::DEFAULT => 1, + ); +} + +function shortArrayWithConstantKey() { + $arr = [ + /* testShortArrayArrowWithClassConstantKey */ + SomeClass::DEFAULT => 1, + ]; +} + +function yieldWithConstantKey() { + /* testYieldArrowWithClassConstantKey */ + yield SomeClass::DEFAULT => 1; +} + +function longArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchArrowWithNestedLongArrayWithClassConstantKey */ + default => array( + /* testLongArrayArrowWithClassConstantKeyNestedInMatch */ + SomeClass::DEFAULT => 1, + ), + }; +} + +function shortArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchArrowWithNestedShortArrayWithClassConstantKey */ + default => [ + /* testShortArrayArrowWithClassConstantKeyNestedInMatch */ + SomeClass::DEFAULT => 1, + ], + }; +} + + +function longArrayWithConstantKeyWithNestedMatch() { + return array( + /* testLongArrayArrowWithClassConstantKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchArrowNestedInLongArrayWithClassConstantKey */ + default => 'foo' + }, + ); +} + +function shortArrayWithConstantKeyWithNestedMatch() { + return [ + /* testShortArrayArrowWithClassConstantKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchArrowNestedInShortArrayWithClassConstantKey */ + default => 'foo' + }, + ]; +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.php new file mode 100644 index 00000000..5258d9c1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.php @@ -0,0 +1,237 @@ + + * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class DoubleArrowTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that "normal" double arrows are correctly tokenized as `T_DOUBLE_ARROW`. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataDoubleArrow + * @coversNothing + * + * @return void + */ + public function testDoubleArrow($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_DOUBLE_ARROW, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_DOUBLE_ARROW (code)'); + $this->assertSame('T_DOUBLE_ARROW', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_DOUBLE_ARROW (type)'); + + }//end testDoubleArrow() + + + /** + * Data provider. + * + * @see testDoubleArrow() + * + * @return array> + */ + public static function dataDoubleArrow() + { + return [ + 'simple_long_array' => ['/* testLongArrayArrowSimple */'], + 'simple_short_array' => ['/* testShortArrayArrowSimple */'], + 'simple_long_list' => ['/* testLongListArrowSimple */'], + 'simple_short_list' => ['/* testShortListArrowSimple */'], + 'simple_yield' => ['/* testYieldArrowSimple */'], + 'simple_foreach' => ['/* testForeachArrowSimple */'], + + 'long_array_with_match_value_1' => ['/* testLongArrayArrowWithNestedMatchValue1 */'], + 'long_array_with_match_value_2' => ['/* testLongArrayArrowWithNestedMatchValue2 */'], + 'short_array_with_match_value_1' => ['/* testShortArrayArrowWithNestedMatchValue1 */'], + 'short_array_with_match_value_2' => ['/* testShortArrayArrowWithNestedMatchValue2 */'], + + 'long_array_with_match_key' => ['/* testLongArrayArrowWithMatchKey */'], + 'short_array_with_match_key' => ['/* testShortArrayArrowWithMatchKey */'], + + 'long_array_in_match_body_1' => ['/* testLongArrayArrowInMatchBody1 */'], + 'long_array_in_match_body_2' => ['/* testLongArrayArrowInMatchBody2 */'], + 'long_array_in_match_body_3' => ['/* testLongArrayArrowInMatchBody3 */'], + 'short_array_in_match_body_1' => ['/* testShortArrayArrowInMatchBody1 */'], + 'short_array_in_match_body_2' => ['/* testShortArrayArrowInMatchBody2 */'], + 'short_array_in_match_body_3' => ['/* testShortArrayArrowInMatchBody3 */'], + + 'short_array_in_match_case_1' => ['/* testShortArrayArrowinMatchCase1 */'], + 'short_array_in_match_case_2' => ['/* testShortArrayArrowinMatchCase2 */'], + 'short_array_in_match_case_3' => ['/* testShortArrayArrowinMatchCase3 */'], + 'long_array_in_match_case_4' => ['/* testLongArrayArrowinMatchCase4 */'], + + 'in_complex_short_array_key_match_value' => ['/* testShortArrayArrowInComplexMatchValueinShortArrayKey */'], + 'in_complex_short_array_toplevel' => ['/* testShortArrayArrowInComplexMatchArrayMismash */'], + 'in_complex_short_array_value_match_value' => ['/* testShortArrayArrowInComplexMatchValueinShortArrayValue */'], + + 'long_list_in_match_body' => ['/* testLongListArrowInMatchBody */'], + 'long_list_in_match_case' => ['/* testLongListArrowInMatchCase */'], + 'short_list_in_match_body' => ['/* testShortListArrowInMatchBody */'], + 'short_list_in_match_case' => ['/* testShortListArrowInMatchCase */'], + 'long_list_with_match_in_key' => ['/* testLongListArrowWithMatchInKey */'], + 'short_list_with_match_in_key' => ['/* testShortListArrowWithMatchInKey */'], + + 'long_array_with_constant_default_in_key' => ['/* testLongArrayArrowWithClassConstantKey */'], + 'short_array_with_constant_default_in_key' => ['/* testShortArrayArrowWithClassConstantKey */'], + 'yield_with_constant_default_in_key' => ['/* testYieldArrowWithClassConstantKey */'], + + 'long_array_with_default_in_key_in_match' => ['/* testLongArrayArrowWithClassConstantKeyNestedInMatch */'], + 'short_array_with_default_in_key_in_match' => ['/* testShortArrayArrowWithClassConstantKeyNestedInMatch */'], + 'long_array_with_default_in_key_with_match' => ['/* testLongArrayArrowWithClassConstantKeyWithNestedMatch */'], + 'short_array_with_default_in_key_with_match' => ['/* testShortArrayArrowWithClassConstantKeyWithNestedMatch */'], + ]; + + }//end dataDoubleArrow() + + + /** + * Test that double arrows in match expressions which are the demarkation between a case and the return value + * are correctly tokenized as `T_MATCH_ARROW`. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataMatchArrow + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testMatchArrow($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_MATCH_ARROW, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_ARROW (code)'); + $this->assertSame('T_MATCH_ARROW', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_ARROW (type)'); + + }//end testMatchArrow() + + + /** + * Data provider. + * + * @see testMatchArrow() + * + * @return array> + */ + public static function dataMatchArrow() + { + return [ + 'single_case' => ['/* testMatchArrowSimpleSingleCase */'], + 'multi_case' => ['/* testMatchArrowSimpleMultiCase */'], + 'single_case_with_trailing_comma' => ['/* testMatchArrowSimpleSingleCaseWithTrailingComma */'], + 'multi_case_with_trailing_comma' => ['/* testMatchArrowSimpleMultiCaseWithTrailingComma */'], + 'match_nested_outer' => ['/* testMatchArrowNestedMatchOuter */'], + 'match_nested_inner' => ['/* testMatchArrowNestedMatchInner */'], + + 'in_long_array_value_1' => ['/* testMatchArrowInLongArrayValue1 */'], + 'in_long_array_value_2' => ['/* testMatchArrowInLongArrayValue2 */'], + 'in_long_array_value_3' => ['/* testMatchArrowInLongArrayValue3 */'], + 'in_short_array_value_1' => ['/* testMatchArrowInShortArrayValue1 */'], + 'in_short_array_value_2' => ['/* testMatchArrowInShortArrayValue2 */'], + 'in_short_array_value_3' => ['/* testMatchArrowInShortArrayValue3 */'], + + 'in_long_array_key_1' => ['/* testMatchArrowInLongArrayKey1 */'], + 'in_long_array_key_2' => ['/* testMatchArrowInLongArrayKey2 */'], + 'in_short_array_key_1' => ['/* testMatchArrowInShortArrayKey1 */'], + 'in_short_array_key_2' => ['/* testMatchArrowInShortArrayKey2 */'], + + 'with_long_array_value_with_keys' => ['/* testMatchArrowWithLongArrayBodyWithKeys */'], + 'with_short_array_value_without_keys' => ['/* testMatchArrowWithShortArrayBodyWithoutKeys */'], + 'with_long_array_value_without_keys' => ['/* testMatchArrowWithLongArrayBodyWithoutKeys */'], + 'with_short_array_value_with_keys' => ['/* testMatchArrowWithShortArrayBodyWithKeys */'], + + 'with_short_array_with_keys_as_case' => ['/* testMatchArrowWithShortArrayWithKeysAsCase */'], + 'with_multiple_arrays_with_keys_as_case' => ['/* testMatchArrowWithMultipleArraysWithKeysAsCase */'], + + 'in_fn_body_case' => ['/* testMatchArrowInFnBody1 */'], + 'in_fn_body_default' => ['/* testMatchArrowInFnBody2 */'], + 'with_fn_body_case' => ['/* testMatchArrowWithFnBody1 */'], + 'with_fn_body_default' => ['/* testMatchArrowWithFnBody2 */'], + + 'in_complex_short_array_key_1' => ['/* testMatchArrowInComplexShortArrayKey1 */'], + 'in_complex_short_array_key_2' => ['/* testMatchArrowInComplexShortArrayKey2 */'], + 'in_complex_short_array_value_1' => ['/* testMatchArrowInComplexShortArrayValue1 */'], + 'in_complex_short_array_value_2' => ['/* testMatchArrowInComplexShortArrayValue2 */'], + + 'with_long_list_in_body' => ['/* testMatchArrowWithLongListBody */'], + 'with_long_list_in_case' => ['/* testMatchArrowWithLongListInCase */'], + 'with_short_list_in_body' => ['/* testMatchArrowWithShortListBody */'], + 'with_short_list_in_case' => ['/* testMatchArrowWithShortListInCase */'], + 'in_long_list_key' => ['/* testMatchArrowInLongListKey */'], + 'in_short_list_key' => ['/* testMatchArrowInShortListKey */'], + + 'with_long_array_value_with_default_key' => ['/* testMatchArrowWithNestedLongArrayWithClassConstantKey */'], + 'with_short_array_value_with_default_key' => ['/* testMatchArrowWithNestedShortArrayWithClassConstantKey */'], + 'in_long_array_value_with_default_key' => ['/* testMatchArrowNestedInLongArrayWithClassConstantKey */'], + 'in_short_array_value_with_default_key' => ['/* testMatchArrowNestedInShortArrayWithClassConstantKey */'], + ]; + + }//end dataMatchArrow() + + + /** + * Test that double arrows used as the scope opener for an arrow function + * are correctly tokenized as `T_FN_ARROW`. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataFnArrow + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testFnArrow($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_FN_ARROW, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_FN_ARROW (code)'); + $this->assertSame('T_FN_ARROW', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_FN_ARROW (type)'); + + }//end testFnArrow() + + + /** + * Data provider. + * + * @see testFnArrow() + * + * @return array> + */ + public static function dataFnArrow() + { + return [ + 'simple_fn' => ['/* testFnArrowSimple */'], + + 'with_match_as_value' => ['/* testFnArrowWithMatchInValue */'], + 'in_match_value_case' => ['/* testFnArrowInMatchBody1 */'], + 'in_match_value_default' => ['/* testFnArrowInMatchBody2 */'], + + 'in_complex_match_value_in_short_array' => ['/* testFnArrowInComplexMatchValueInShortArrayValue */'], + ]; + + }//end dataFnArrow() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.inc new file mode 100644 index 00000000..62535b1e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.inc @@ -0,0 +1,52 @@ +bar"; +/* testProperty2 */ +"{$foo->bar}"; + +/* testMethod1 */ +"{$foo->bar()}"; + +/* testClosure1 */ +"{$foo()}"; + +/* testChain1 */ +"{$foo['bar']->baz()()}"; + +/* testVariableVar1 */ +"${$bar}"; +/* testVariableVar2 */ +"${(foo)}"; +/* testVariableVar3 */ +"${foo->bar}"; + +/* testNested1 */ +"${foo["${bar}"]}"; +/* testNested2 */ +"${foo["${bar['baz']}"]}"; +/* testNested3 */ +"${foo->{$baz}}"; +/* testNested4 */ +"${foo->{${'a'}}}"; +/* testNested5 */ +"${foo->{"${'a'}"}}"; + +/* testParseError */ +"${foo["${bar diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.php new file mode 100644 index 00000000..aa0817a4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.php @@ -0,0 +1,144 @@ + + * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class DoubleQuotedStringTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that double quoted strings contain the complete string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent The expected content of the double quoted string. + * + * @dataProvider dataDoubleQuotedString + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testDoubleQuotedString($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $target = $this->getTargetToken($testMarker, T_DOUBLE_QUOTED_STRING); + $this->assertSame($expectedContent, $tokens[$target]['content']); + + }//end testDoubleQuotedString() + + + /** + * Data provider. + * + * Type reference: + * 1. Directly embedded variables. + * 2. Braces outside the variable. + * 3. Braces after the dollar sign. + * 4. Variable variables and expressions. + * + * @link https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation + * + * @see testDoubleQuotedString() + * + * @return array> + */ + public static function dataDoubleQuotedString() + { + return [ + 'Type 1: simple variable' => [ + 'testMarker' => '/* testSimple1 */', + 'expectedContent' => '"$foo"', + ], + 'Type 2: simple variable' => [ + 'testMarker' => '/* testSimple2 */', + 'expectedContent' => '"{$foo}"', + ], + 'Type 3: simple variable' => [ + 'testMarker' => '/* testSimple3 */', + 'expectedContent' => '"${foo}"', + ], + 'Type 1: array offset' => [ + 'testMarker' => '/* testDIM1 */', + 'expectedContent' => '"$foo[bar]"', + ], + 'Type 2: array offset' => [ + 'testMarker' => '/* testDIM2 */', + 'expectedContent' => '"{$foo[\'bar\']}"', + ], + 'Type 3: array offset' => [ + 'testMarker' => '/* testDIM3 */', + 'expectedContent' => '"${foo[\'bar\']}"', + ], + 'Type 1: object property' => [ + 'testMarker' => '/* testProperty1 */', + 'expectedContent' => '"$foo->bar"', + ], + 'Type 2: object property' => [ + 'testMarker' => '/* testProperty2 */', + 'expectedContent' => '"{$foo->bar}"', + ], + 'Type 2: object method call' => [ + 'testMarker' => '/* testMethod1 */', + 'expectedContent' => '"{$foo->bar()}"', + ], + 'Type 2: closure function call' => [ + 'testMarker' => '/* testClosure1 */', + 'expectedContent' => '"{$foo()}"', + ], + 'Type 2: chaining various syntaxes' => [ + 'testMarker' => '/* testChain1 */', + 'expectedContent' => '"{$foo[\'bar\']->baz()()}"', + ], + 'Type 4: variable variables' => [ + 'testMarker' => '/* testVariableVar1 */', + 'expectedContent' => '"${$bar}"', + ], + 'Type 4: variable constants' => [ + 'testMarker' => '/* testVariableVar2 */', + 'expectedContent' => '"${(foo)}"', + ], + 'Type 4: object property' => [ + 'testMarker' => '/* testVariableVar3 */', + 'expectedContent' => '"${foo->bar}"', + ], + 'Type 4: variable variable nested in array offset' => [ + 'testMarker' => '/* testNested1 */', + 'expectedContent' => '"${foo["${bar}"]}"', + ], + 'Type 4: variable array offset nested in array offset' => [ + 'testMarker' => '/* testNested2 */', + 'expectedContent' => '"${foo["${bar[\'baz\']}"]}"', + ], + 'Type 4: variable object property' => [ + 'testMarker' => '/* testNested3 */', + 'expectedContent' => '"${foo->{$baz}}"', + ], + 'Type 4: variable object property - complex with single quotes' => [ + 'testMarker' => '/* testNested4 */', + 'expectedContent' => '"${foo->{${\'a\'}}}"', + ], + 'Type 4: variable object property - complex with single and double quotes' => [ + 'testMarker' => '/* testNested5 */', + 'expectedContent' => '"${foo->{"${\'a\'}"}}"', + ], + 'Type 4: live coding/parse error' => [ + 'testMarker' => '/* testParseError */', + 'expectedContent' => '"${foo["${bar +', + ], + ]; + + }//end dataDoubleQuotedString() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.inc new file mode 100644 index 00000000..13b87242 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.inc @@ -0,0 +1,95 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class EnumCaseTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the enum "case" is converted to T_ENUM_CASE. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataEnumCases + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testEnumCases($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCase = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$enumCase]; + + $this->assertSame(T_ENUM_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (code)'); + $this->assertSame('T_ENUM_CASE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (type)'); + + }//end testEnumCases() + + + /** + * Data provider. + * + * @see testEnumCases() + * + * @return array> + */ + public static function dataEnumCases() + { + return [ + 'enum case, no value' => ['/* testPureEnumCase */'], + 'enum case, integer value' => ['/* testBackingIntegerEnumCase */'], + 'enum case, string value' => ['/* testBackingStringEnumCase */'], + 'enum case, integer value in more complex enum' => ['/* testEnumCaseInComplexEnum */'], + 'enum case, keyword in mixed case' => ['/* testEnumCaseIsCaseInsensitive */'], + 'enum case, after switch statement' => ['/* testEnumCaseAfterSwitch */'], + 'enum case, after switch statement using alternative syntax' => ['/* testEnumCaseAfterSwitchWithEndSwitch */'], + ]; + + }//end dataEnumCases() + + + /** + * Test that "case" that is not enum case is still tokenized as `T_CASE`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataNotEnumCases + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNotEnumCases($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $case = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$case]; + + $this->assertSame(T_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (code)'); + $this->assertSame('T_CASE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (type)'); + + }//end testNotEnumCases() + + + /** + * Data provider. + * + * @see testNotEnumCases() + * + * @return array> + */ + public static function dataNotEnumCases() + { + return [ + 'switch case with constant, semicolon condition end' => ['/* testCaseWithSemicolonIsNotEnumCase */'], + 'switch case with constant, colon condition end' => ['/* testCaseWithConstantIsNotEnumCase */'], + 'switch case with constant, comparison' => ['/* testCaseWithConstantAndIdenticalIsNotEnumCase */'], + 'switch case with constant, assignment' => ['/* testCaseWithAssigmentToConstantIsNotEnumCase */'], + 'switch case with constant, keyword in mixed case' => ['/* testIsNotEnumCaseIsCaseInsensitive */'], + 'switch case, body in curlies declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch1 */'], + 'switch case, body after semicolon declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch2 */'], + ]; + + }//end dataNotEnumCases() + + + /** + * Test that "case" that is not enum case is still tokenized as `T_CASE`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataKeywordAsEnumCaseNameShouldBeString + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testKeywordAsEnumCaseNameShouldBeString($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCaseName = $this->getTargetToken($testMarker, [T_STRING, T_INTERFACE, T_TRAIT, T_ENUM, T_FUNCTION, T_FALSE, T_DEFAULT, T_ARRAY]); + $tokenArray = $tokens[$enumCaseName]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testKeywordAsEnumCaseNameShouldBeString() + + + /** + * Data provider. + * + * @see testKeywordAsEnumCaseNameShouldBeString() + * + * @return array> + */ + public static function dataKeywordAsEnumCaseNameShouldBeString() + { + return [ + '"interface" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString1 */'], + '"trait" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString2 */'], + '"enum" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString3 */'], + '"function" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString4 */'], + '"false" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString5 */'], + '"default" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString6 */'], + '"array" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString7 */'], + ]; + + }//end dataKeywordAsEnumCaseNameShouldBeString() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.inc new file mode 100644 index 00000000..e65600b6 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.inc @@ -0,0 +1,40 @@ +finally = 'foo'; + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.php new file mode 100644 index 00000000..e73dde12 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.php @@ -0,0 +1,98 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class FinallyTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the finally keyword is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataFinallyKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testFinallyKeyword($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_FINALLY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_FINALLY (code)'); + $this->assertSame('T_FINALLY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_FINALLY (type)'); + + }//end testFinallyKeyword() + + + /** + * Data provider. + * + * @see testFinallyKeyword() + * + * @return array> + */ + public static function dataFinallyKeyword() + { + return [ + 'finally after try and catch' => ['/* testTryCatchFinally */'], + 'finally between try and catch' => ['/* testTryFinallyCatch */'], + 'finally after try, no catch' => ['/* testTryFinally */'], + ]; + + }//end dataFinallyKeyword() + + + /** + * Test that 'finally' when not used as the reserved keyword is tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataFinallyNonKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testFinallyNonKeyword($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testFinallyNonKeyword() + + + /** + * Data provider. + * + * @see testFinallyNonKeyword() + * + * @return array> + */ + public static function dataFinallyNonKeyword() + { + return [ + 'finally used as class constant name' => ['/* testFinallyUsedAsClassConstantName */'], + 'finally used as method name' => ['/* testFinallyUsedAsMethodName */'], + 'finally used as property name' => ['/* testFinallyUsedAsPropertyName */'], + ]; + + }//end dataFinallyNonKeyword() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.inc new file mode 100644 index 00000000..249064a2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.inc @@ -0,0 +1,85 @@ + +
+ + + +
+ +
+ + property: + // Do something. + break; +} + +switch (true) { + /* testNotGotoDeclarationGlobalConstantInTernary */ + case $x === ($cond) ? CONST_A : CONST_B: + // Do something. + break; +} + +/* testNotGotoDeclarationEnumWithType */ +enum Suit: string implements Colorful, CardGame {} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.php new file mode 100644 index 00000000..09bb6fe2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.php @@ -0,0 +1,194 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the tokenization of goto declarations and statements. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class GotoLabelTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that the label in a goto statement is tokenized as T_STRING. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to expect. + * + * @dataProvider dataGotoStatement + * + * @return void + */ + public function testGotoStatement($testMarker, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken($testMarker, T_STRING); + + $this->assertTrue(is_int($label)); + $this->assertSame($testContent, $tokens[$label]['content']); + + }//end testGotoStatement() + + + /** + * Data provider. + * + * @see testGotoStatement() + * + * @return array> + */ + public static function dataGotoStatement() + { + return [ + 'label for goto statement' => [ + 'testMarker' => '/* testGotoStatement */', + 'testContent' => 'marker', + ], + 'label for goto statement in loop, keyword capitalized' => [ + 'testMarker' => '/* testGotoStatementInLoop */', + 'testContent' => 'end', + ], + 'label for goto statement in switch' => [ + 'testMarker' => '/* testGotoStatementInSwitch */', + 'testContent' => 'def', + ], + 'label for goto statement within function' => [ + 'testMarker' => '/* testGotoStatementInFunction */', + 'testContent' => 'label', + ], + ]; + + }//end dataGotoStatement() + + + /** + * Verify that the label in a goto declaration is tokenized as T_GOTO_LABEL. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to expect. + * + * @dataProvider dataGotoDeclaration + * + * @return void + */ + public function testGotoDeclaration($testMarker, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken($testMarker, T_GOTO_LABEL); + + $this->assertTrue(is_int($label)); + $this->assertSame($testContent, $tokens[$label]['content']); + + }//end testGotoDeclaration() + + + /** + * Data provider. + * + * @see testGotoDeclaration() + * + * @return array> + */ + public static function dataGotoDeclaration() + { + return [ + 'label in goto declaration - marker' => [ + 'testMarker' => '/* testGotoDeclaration */', + 'testContent' => 'marker:', + ], + 'label in goto declaration - end' => [ + 'testMarker' => '/* testGotoDeclarationOutsideLoop */', + 'testContent' => 'end:', + ], + 'label in goto declaration - def' => [ + 'testMarker' => '/* testGotoDeclarationInSwitch */', + 'testContent' => 'def:', + ], + 'label in goto declaration - label' => [ + 'testMarker' => '/* testGotoDeclarationInFunction */', + 'testContent' => 'label:', + ], + ]; + + }//end dataGotoDeclaration() + + + /** + * Verify that the constant used in a switch - case statement is not confused with a goto label. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to expect. + * + * @dataProvider dataNotAGotoDeclaration + * + * @return void + */ + public function testNotAGotoDeclaration($testMarker, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_GOTO_LABEL, T_STRING], $testContent); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotAGotoDeclaration() + + + /** + * Data provider. + * + * @see testNotAGotoDeclaration() + * + * @return array> + */ + public static function dataNotAGotoDeclaration() + { + return [ + 'not goto label - global constant followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationGlobalConstant */', + 'testContent' => 'CONSTANT', + ], + 'not goto label - namespaced constant followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationNamespacedConstant */', + 'testContent' => 'CONSTANT', + ], + 'not goto label - class constant followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationClassConstant */', + 'testContent' => 'CONSTANT', + ], + 'not goto label - class property use followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationClassProperty */', + 'testContent' => 'property', + ], + 'not goto label - global constant followed by ternary else' => [ + 'testMarker' => '/* testNotGotoDeclarationGlobalConstantInTernary */', + 'testContent' => 'CONST_A', + ], + 'not goto label - global constant after ternary else' => [ + 'testMarker' => '/* testNotGotoDeclarationGlobalConstantInTernary */', + 'testContent' => 'CONST_B', + ], + 'not goto label - name of backed enum' => [ + 'testMarker' => '/* testNotGotoDeclarationEnumWithType */', + 'testContent' => 'Suit', + ], + ]; + + }//end dataNotAGotoDeclaration() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocNowdocTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocNowdocTest.inc new file mode 100644 index 00000000..5041dda1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocNowdocTest.inc @@ -0,0 +1,39 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests the tokenization for heredoc/nowdoc constructs. + * + * Verifies that: + * - Nowdoc opener/closers are retokenized from `T_[START_|END_]HEREDOC` to `T_[START_|END_]NOWDOC`. + * - The contents of the heredoc/nowdoc is tokenized as `T_HEREDOC`/`T_NOWDOC`. + * - Each line of the contents has its own token, which includes the new line char. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class HeredocNowdocTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify tokenization a heredoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testHeredocSingleLine() + { + $expectedSequence = [ + [T_START_HEREDOC => '<< 'Some $var text'."\n"], + [T_END_HEREDOC => 'EOD'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_HEREDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testHeredocSingleLine() + + + /** + * Verify tokenization a nowdoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testNowdocSingleLine() + { + $expectedSequence = [ + [T_START_NOWDOC => "<<<'MARKER'\n"], + [T_NOWDOC => 'Some text'."\n"], + [T_END_NOWDOC => 'MARKER'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_NOWDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testNowdocSingleLine() + + + /** + * Verify tokenization a multiline heredoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testHeredocMultiLine() + { + $expectedSequence = [ + [T_START_HEREDOC => '<<<"😬"'."\n"], + [T_HEREDOC => 'Lorum ipsum'."\n"], + [T_HEREDOC => 'Some $var text'."\n"], + [T_HEREDOC => 'dolor sit amet'."\n"], + [T_END_HEREDOC => '😬'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_HEREDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testHeredocMultiLine() + + + /** + * Verify tokenization a multiline testNowdocSingleLine construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testNowdocMultiLine() + { + $expectedSequence = [ + [T_START_NOWDOC => "<<<'multi_line'\n"], + [T_NOWDOC => 'Lorum ipsum'."\n"], + [T_NOWDOC => 'Some text'."\n"], + [T_NOWDOC => 'dolor sit amet'."\n"], + [T_END_NOWDOC => 'multi_line'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_NOWDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testNowdocMultiLine() + + + /** + * Verify tokenization a multiline heredoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testHeredocEndsOnBlankLine() + { + $expectedSequence = [ + [T_START_HEREDOC => '<< 'Lorum ipsum'."\n"], + [T_HEREDOC => 'dolor sit amet'."\n"], + [T_HEREDOC => "\n"], + [T_END_HEREDOC => 'EOD'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_HEREDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testHeredocEndsOnBlankLine() + + + /** + * Verify tokenization a multiline testNowdocSingleLine construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testNowdocEndsOnBlankLine() + { + $expectedSequence = [ + [T_START_NOWDOC => "<<<'EOD'\n"], + [T_NOWDOC => 'Lorum ipsum'."\n"], + [T_NOWDOC => 'dolor sit amet'."\n"], + [T_NOWDOC => "\n"], + [T_END_NOWDOC => 'EOD'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_NOWDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testNowdocEndsOnBlankLine() + + + /** + * Test helper. Check a token sequence complies with an expected token sequence. + * + * @param int $startPtr The position in the file to start checking from. + * @param array> $expectedSequence The consecutive token constants and their contents to expect. + * + * @return void + */ + private function checkTokenSequence($startPtr, array $expectedSequence) + { + $tokens = $this->phpcsFile->getTokens(); + + $sequenceKey = 0; + $sequenceCount = count($expectedSequence); + + for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++, $sequenceKey++) { + $currentItem = $expectedSequence[$sequenceKey]; + $expectedCode = key($currentItem); + $expectedType = Tokens::tokenName($expectedCode); + $expectedContent = current($currentItem); + $errorMsgSuffix = PHP_EOL.'(StackPtr: '.$i.' | Position in sequence: '.$sequenceKey.' | Expected: '.$expectedType.')'; + + $this->assertSame( + $expectedCode, + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedType.' (code)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedType, + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedType.' (type)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedContent, + $tokens[$i]['content'], + 'Token content did not match expectations'.$errorMsgSuffix + ); + }//end for + + }//end checkTokenSequence() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.inc new file mode 100644 index 00000000..d552b128 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.inc @@ -0,0 +1,11 @@ +>>>>>> master diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.php new file mode 100644 index 00000000..877706fb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.php @@ -0,0 +1,41 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the tokenization for an unclosed heredoc construct. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class HeredocParseErrorTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that a heredoc (and nowdoc) start token is retokenized to T_STRING if no closer is found. + * + * @return void + */ + public function testMergeConflict() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testUnclosedHeredoc */', [T_START_HEREDOC, T_STRING], '<<< HEAD'."\n"); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_START_HEREDOC (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_START_HEREDOC (type)'); + + }//end testMergeConflict() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.inc new file mode 100644 index 00000000..ae43e24a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.inc @@ -0,0 +1,193 @@ +bar +EOD; + +/* testProperty2 */ +$heredoc = <<<"EOD" +{$foo->bar} +EOD; + +/* testMethod1 */ +$heredoc = <<bar()} +EOD; + +/* testClosure1 */ +$heredoc = <<<"EOD" +{$foo()} +EOD; + +/* testChain1 */ +$heredoc = <<baz()()} +EOD; + +/* testVariableVar1 */ +$heredoc = <<<"EOD" +${$bar} +EOD; + +/* testVariableVar2 */ +$heredoc = <<bar} +EOD; + +/* testNested1 */ +$heredoc = <<{$baz}} +EOD; + +/* testNested4 */ +$heredoc = <<<"EOD" +${foo->{${'a'}}} +EOD; + +/* testNested5 */ +$heredoc = <<{"${'a'}"}} +EOD; + +/* testSimple1Wrapped */ +$heredoc = <<bar Something +EOD; + +/* testProperty2Wrapped */ +$heredoc = <<<"EOD" +Do {$foo->bar} Something +EOD; + +/* testMethod1Wrapped */ +$heredoc = <<bar()} Something +EOD; + +/* testClosure1Wrapped */ +$heredoc = <<<"EOD" +Do {$foo()} Something +EOD; + +/* testChain1Wrapped */ +$heredoc = <<baz()()} Something +EOD; + +/* testVariableVar1Wrapped */ +$heredoc = <<<"EOD" +Do ${$bar} Something +EOD; + +/* testVariableVar2Wrapped */ +$heredoc = <<bar} Something +EOD; + +/* testNested1Wrapped */ +$heredoc = <<{$baz}} Something +EOD; + +/* testNested4Wrapped */ +$heredoc = <<<"EOD" +Do ${foo->{${'a'}}} Something +EOD; + +/* testNested5Wrapped */ +$heredoc = <<{"${'a'}"}} Something +EOD; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.php new file mode 100644 index 00000000..c31c1753 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.php @@ -0,0 +1,161 @@ + + * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class HeredocStringTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that heredoc strings contain the complete interpolated string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent The expected content of the heredoc string. + * + * @dataProvider dataHeredocString + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testHeredocString($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $target = $this->getTargetToken($testMarker, T_HEREDOC); + $this->assertSame($expectedContent."\n", $tokens[$target]['content']); + + }//end testHeredocString() + + + /** + * Test that heredoc strings contain the complete interpolated string when combined with other texts. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent The expected content of the heredoc string. + * + * @dataProvider dataHeredocString + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testHeredocStringWrapped($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $testMarker = substr($testMarker, 0, -3).'Wrapped */'; + $target = $this->getTargetToken($testMarker, T_HEREDOC); + $this->assertSame('Do '.$expectedContent." Something\n", $tokens[$target]['content']); + + }//end testHeredocStringWrapped() + + + /** + * Data provider. + * + * Type reference: + * 1. Directly embedded variables. + * 2. Braces outside the variable. + * 3. Braces after the dollar sign. + * 4. Variable variables and expressions. + * + * @link https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation + * + * @see testHeredocString() + * + * @return array> + */ + public static function dataHeredocString() + { + return [ + 'Type 1: simple variable' => [ + 'testMarker' => '/* testSimple1 */', + 'expectedContent' => '$foo', + ], + 'Type 2: simple variable' => [ + 'testMarker' => '/* testSimple2 */', + 'expectedContent' => '{$foo}', + ], + 'Type 3: simple variable' => [ + 'testMarker' => '/* testSimple3 */', + 'expectedContent' => '${foo}', + ], + 'Type 1: array offset' => [ + 'testMarker' => '/* testDIM1 */', + 'expectedContent' => '$foo[bar]', + ], + 'Type 2: array offset' => [ + 'testMarker' => '/* testDIM2 */', + 'expectedContent' => '{$foo[\'bar\']}', + ], + 'Type 3: array offset' => [ + 'testMarker' => '/* testDIM3 */', + 'expectedContent' => '${foo[\'bar\']}', + ], + 'Type 1: object property' => [ + 'testMarker' => '/* testProperty1 */', + 'expectedContent' => '$foo->bar', + ], + 'Type 2: object property' => [ + 'testMarker' => '/* testProperty2 */', + 'expectedContent' => '{$foo->bar}', + ], + 'Type 2: object method call' => [ + 'testMarker' => '/* testMethod1 */', + 'expectedContent' => '{$foo->bar()}', + ], + 'Type 2: closure function call' => [ + 'testMarker' => '/* testClosure1 */', + 'expectedContent' => '{$foo()}', + ], + 'Type 2: chaining various syntaxes' => [ + 'testMarker' => '/* testChain1 */', + 'expectedContent' => '{$foo[\'bar\']->baz()()}', + ], + 'Type 4: variable variables' => [ + 'testMarker' => '/* testVariableVar1 */', + 'expectedContent' => '${$bar}', + ], + 'Type 4: variable constants' => [ + 'testMarker' => '/* testVariableVar2 */', + 'expectedContent' => '${(foo)}', + ], + 'Type 4: object property' => [ + 'testMarker' => '/* testVariableVar3 */', + 'expectedContent' => '${foo->bar}', + ], + 'Type 4: variable variable nested in array offset' => [ + 'testMarker' => '/* testNested1 */', + 'expectedContent' => '${foo["${bar}"]}', + ], + 'Type 4: variable array offset nested in array offset' => [ + 'testMarker' => '/* testNested2 */', + 'expectedContent' => '${foo["${bar[\'baz\']}"]}', + ], + 'Type 4: variable object property' => [ + 'testMarker' => '/* testNested3 */', + 'expectedContent' => '${foo->{$baz}}', + ], + 'Type 4: variable object property - complex with single quotes' => [ + 'testMarker' => '/* testNested4 */', + 'expectedContent' => '${foo->{${\'a\'}}}', + ], + 'Type 4: variable object property - complex with single and double quotes' => [ + 'testMarker' => '/* testNested5 */', + 'expectedContent' => '${foo->{"${\'a\'}"}}', + ], + ]; + + }//end dataHeredocString() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.inc new file mode 100644 index 00000000..2f1d20bf --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.inc @@ -0,0 +1,407 @@ +getPos(skip: false), + count: count(array_or_countable: $array), + value: 50 +); + +array_fill( + start_index: /* testNestedFunctionCallInner1 */ $obj->getPos(skip: false), + count: /* testNestedFunctionCallInner2 */ count(array_or_countable: $array), + value: 50 +); + +/* testNamespaceRelativeFunction */ +namespace\function_name(label:$string, more: false); + +/* testPartiallyQualifiedFunction */ +Partially\Qualified\function_name(label:$string, more: false); + +/* testFullyQualifiedFunction */ +\Fully\Qualified\function_name(label: $string, more:false); + +/* testVariableFunction */ +$fn(label: $string, more:false); + +/* testVariableVariableFunction */ +${$fn}(label: $string, more:false); + +/* testMethodCall */ +$obj->methodName(label: $foo, more: $bar); + +/* testVariableMethodCall */ +$obj->{$var}(label: $foo, more: $bar); + +/* testClassInstantiation */ +$obj = new MyClass(label: $string, more:false); + +/* testClassInstantiationSelf */ +$obj = new self(label: $string, more:true); + +/* testClassInstantiationStatic */ +$obj = new static(label: $string, more:false); + +/* testAnonClass */ +$anon = new class(label: $string, more: false) { + public function __construct($label, $more) {} +}; + +function myfoo( $💩💩💩, $Пасха, $_valid) {} +/* testNonAsciiNames */ +foo(💩💩💩: [], Пасха: 'text', _valid: 123); + +/* testMixedPositionalAndNamedArgsWithTernary */ +foo( $cond ? true : false, name: $value2 ); + +/* testNamedArgWithTernary */ +foo( label: $cond ? true : false, more: $cond ? CONSTANT_A : CONSTANT_B ); + +/* testTernaryWithFunctionCallsInThenElse */ +echo $cond ? foo( label: $something ) : foo( more: $something_else ); + +/* testTernaryWithConstantsInThenElse */ +echo $cond ? CONSTANT_NAME : OTHER_CONSTANT; + +switch ($s) { + /* testSwitchCaseWithConstant */ + case MY_CONSTANT: + // Do something. + break; + + /* testSwitchCaseWithClassProperty */ + case $obj->property: + // Do something. + break; + + /* testSwitchDefault */ + default: + // Do something. + break; +} + +/* testTernaryWithClosuresAndReturnTypes */ +$closure = $cond ? function() : bool {return true;} : function() : int {return 123;}; + +/* testTernaryWithArrowFunctionsAndReturnTypes */ +$fn = $cond ? fn() : bool => true : fn() : int => 123; + + +/* testCompileErrorNamedBeforePositional */ +// Not the concern of PHPCS. Should still be handled. +test(param: $bar, $foo); + +/* testDuplicateName1 */ +// Error Exception, but not the concern of PHPCS. Should still be handled. +test(param: 1, /* testDuplicateName2 */ param: 2); + +/* testIncorrectOrderWithVariadic */ +// Error Exception, but not the concern of PHPCS. Should still be handled. +array_fill(start_index: 0, ...[100, 50]); + +/* testCompileErrorIncorrectOrderWithVariadic */ +// Not the concern of PHPCS. Should still be handled. +test(...$values, param: $value); // Compile-time error + +/* testParseErrorNoValue */ +// Not the concern of PHPCS. Should still be handled. +test(param1:, param2:); + +/* testParseErrorDynamicName */ +// Parse error. Ignore. +function_name($variableStoringParamName: $value); + +/* testParseErrorExit */ +// Exit is a language construct, not a function. Named params not supported, handle it anyway. +exit(status: $value); + +/* testParseErrorEmpty */ +// Empty is a language construct, not a function. Named params not supported, handle it anyway. +empty(variable: $value); + +/* testParseErrorEval */ +// Eval is a language construct, not a function. Named params not supported, handle it anyway. +eval(code: $value); + +/* testParseErrorArbitraryParentheses */ +// Parse error. Not named param, handle it anyway. +$calc = (something: $value / $other); + + +/* testReservedKeywordAbstract1 */ +foobar(abstract: $value, /* testReservedKeywordAbstract2 */ abstract: $value); + +/* testReservedKeywordAnd1 */ +foobar(and: $value, /* testReservedKeywordAnd2 */ and: $value); + +/* testReservedKeywordArray1 */ +foobar(array: $value, /* testReservedKeywordArray2 */ array: $value); + +/* testReservedKeywordAs1 */ +foobar(as: $value, /* testReservedKeywordAs2 */ as: $value); + +/* testReservedKeywordBreak1 */ +foobar(break: $value, /* testReservedKeywordBreak2 */ break: $value); + +/* testReservedKeywordCallable1 */ +foobar(callable: $value, /* testReservedKeywordCallable2 */ callable: $value); + +/* testReservedKeywordCase1 */ +foobar(case: $value, /* testReservedKeywordCase2 */ case: $value); + +/* testReservedKeywordCatch1 */ +foobar(catch: $value, /* testReservedKeywordCatch2 */ catch: $value); + +/* testReservedKeywordClass1 */ +foobar(class: $value, /* testReservedKeywordClass2 */ class: $value); + +/* testReservedKeywordClone1 */ +foobar(clone: $value, /* testReservedKeywordClone2 */ clone: $value); + +/* testReservedKeywordConst1 */ +foobar(const: $value, /* testReservedKeywordConst2 */ const: $value); + +/* testReservedKeywordContinue1 */ +foobar(continue: $value, /* testReservedKeywordContinue2 */ continue: $value); + +/* testReservedKeywordDeclare1 */ +foobar(declare: $value, /* testReservedKeywordDeclare2 */ declare: $value); + +/* testReservedKeywordDefault1 */ +foobar(default: $value, /* testReservedKeywordDefault2 */ default: $value); + +/* testReservedKeywordDie1 */ +foobar(die: $value, /* testReservedKeywordDie2 */ die: $value); + +/* testReservedKeywordDo1 */ +foobar(do: $value, /* testReservedKeywordDo2 */ do: $value); + +/* testReservedKeywordEcho1 */ +foobar(echo: $value, /* testReservedKeywordEcho2 */ echo: $value); + +/* testReservedKeywordElse1 */ +foobar(else: $value, /* testReservedKeywordElse2 */ else: $value); + +/* testReservedKeywordElseif1 */ +foobar(elseif: $value, /* testReservedKeywordElseif2 */ elseif: $value); + +/* testReservedKeywordEmpty1 */ +foobar(empty: $value, /* testReservedKeywordEmpty2 */ empty: $value); + +/* testReservedKeywordEnum1 */ +foobar(enum: $value, /* testReservedKeywordEnum2 */ enum: $value); + +/* testReservedKeywordEnddeclare1 */ +foobar(enddeclare: $value, /* testReservedKeywordEnddeclare2 */ enddeclare: $value); + +/* testReservedKeywordEndfor1 */ +foobar(endfor: $value, /* testReservedKeywordEndfor2 */ endfor: $value); + +/* testReservedKeywordEndforeach1 */ +foobar(endforeach: $value, /* testReservedKeywordEndforeach2 */ endforeach: $value); + +/* testReservedKeywordEndif1 */ +foobar(endif: $value, /* testReservedKeywordEndif2 */ endif: $value); + +/* testReservedKeywordEndswitch1 */ +foobar(endswitch: $value, /* testReservedKeywordEndswitch2 */ endswitch: $value); + +/* testReservedKeywordEndwhile1 */ +foobar(endwhile: $value, /* testReservedKeywordEndwhile2 */ endwhile: $value); + +/* testReservedKeywordEval1 */ +foobar(eval: $value, /* testReservedKeywordEval2 */ eval: $value); + +/* testReservedKeywordExit1 */ +foobar(exit: $value, /* testReservedKeywordExit2 */ exit: $value); + +/* testReservedKeywordExtends1 */ +foobar(extends: $value, /* testReservedKeywordExtends2 */ extends: $value); + +/* testReservedKeywordFinal1 */ +foobar(final: $value, /* testReservedKeywordFinal2 */ final: $value); + +/* testReservedKeywordFinally1 */ +foobar(finally: $value, /* testReservedKeywordFinally2 */ finally: $value); + +/* testReservedKeywordFn1 */ +foobar(fn: $value, /* testReservedKeywordFn2 */ fn: $value); + +/* testReservedKeywordFor1 */ +foobar(for: $value, /* testReservedKeywordFor2 */ for: $value); + +/* testReservedKeywordForeach1 */ +foobar(foreach: $value, /* testReservedKeywordForeach2 */ foreach: $value); + +/* testReservedKeywordFunction1 */ +foobar(function: $value, /* testReservedKeywordFunction2 */ function: $value); + +/* testReservedKeywordGlobal1 */ +foobar(global: $value, /* testReservedKeywordGlobal2 */ global: $value); + +/* testReservedKeywordGoto1 */ +foobar(goto: $value, /* testReservedKeywordGoto2 */ goto: $value); + +/* testReservedKeywordIf1 */ +foobar(if: $value, /* testReservedKeywordIf2 */ if: $value); + +/* testReservedKeywordImplements1 */ +foobar(implements: $value, /* testReservedKeywordImplements2 */ implements: $value); + +/* testReservedKeywordInclude1 */ +foobar(include: $value, /* testReservedKeywordInclude2 */ include: $value); + +/* testReservedKeywordInclude_once1 */ +foobar(include_once: $value, /* testReservedKeywordInclude_once2 */ include_once: $value); + +/* testReservedKeywordInstanceof1 */ +foobar(instanceof: $value, /* testReservedKeywordInstanceof2 */ instanceof: $value); + +/* testReservedKeywordInsteadof1 */ +foobar(insteadof: $value, /* testReservedKeywordInsteadof2 */ insteadof: $value); + +/* testReservedKeywordInterface1 */ +foobar(interface: $value, /* testReservedKeywordInterface2 */ interface: $value); + +/* testReservedKeywordIsset1 */ +foobar(isset: $value, /* testReservedKeywordIsset2 */ isset: $value); + +/* testReservedKeywordList1 */ +foobar(list: $value, /* testReservedKeywordList2 */ list: $value); + +/* testReservedKeywordMatch1 */ +foobar(match: $value, /* testReservedKeywordMatch2 */ match: $value); + +/* testReservedKeywordNamespace1 */ +foobar(namespace: $value, /* testReservedKeywordNamespace2 */ namespace: $value); + +/* testReservedKeywordNew1 */ +foobar(new: $value, /* testReservedKeywordNew2 */ new: $value); + +/* testReservedKeywordOr1 */ +foobar(or: $value, /* testReservedKeywordOr2 */ or: $value); + +/* testReservedKeywordPrint1 */ +foobar(print: $value, /* testReservedKeywordPrint2 */ print: $value); + +/* testReservedKeywordPrivate1 */ +foobar(private: $value, /* testReservedKeywordPrivate2 */ private: $value); + +/* testReservedKeywordProtected1 */ +foobar(protected: $value, /* testReservedKeywordProtected2 */ protected: $value); + +/* testReservedKeywordPublic1 */ +foobar(public: $value, /* testReservedKeywordPublic2 */ public: $value); + +/* testReservedKeywordReadonly1 */ +foobar(readonly: $value, /* testReservedKeywordReadonly2 */ readonly: $value); + +/* testReservedKeywordRequire1 */ +foobar(require: $value, /* testReservedKeywordRequire2 */ require: $value); + +/* testReservedKeywordRequire_once1 */ +foobar(require_once: $value, /* testReservedKeywordRequire_once2 */ require_once: $value); + +/* testReservedKeywordReturn1 */ +foobar(return: $value, /* testReservedKeywordReturn2 */ return: $value); + +/* testReservedKeywordStatic1 */ +foobar(static: $value, /* testReservedKeywordStatic2 */ static: $value); + +/* testReservedKeywordSwitch1 */ +foobar(switch: $value, /* testReservedKeywordSwitch2 */ switch: $value); + +/* testReservedKeywordThrow1 */ +foobar(throw: $value, /* testReservedKeywordThrow2 */ throw: $value); + +/* testReservedKeywordTrait1 */ +foobar(trait: $value, /* testReservedKeywordTrait2 */ trait: $value); + +/* testReservedKeywordTry1 */ +foobar(try: $value, /* testReservedKeywordTry2 */ try: $value); + +/* testReservedKeywordUnset1 */ +foobar(unset: $value, /* testReservedKeywordUnset2 */ unset: $value); + +/* testReservedKeywordUse1 */ +foobar(use: $value, /* testReservedKeywordUse2 */ use: $value); + +/* testReservedKeywordVar1 */ +foobar(var: $value, /* testReservedKeywordVar2 */ var: $value); + +/* testReservedKeywordWhile1 */ +foobar(while: $value, /* testReservedKeywordWhile2 */ while: $value); + +/* testReservedKeywordXor1 */ +foobar(xor: $value, /* testReservedKeywordXor2 */ xor: $value); + +/* testReservedKeywordYield1 */ +foobar(yield: $value, /* testReservedKeywordYield2 */ yield: $value); + +/* testReservedKeywordInt1 */ +foobar(int: $value, /* testReservedKeywordInt2 */ int: $value); + +/* testReservedKeywordFloat1 */ +foobar(float: $value, /* testReservedKeywordFloat2 */ float: $value); + +/* testReservedKeywordBool1 */ +foobar(bool: $value, /* testReservedKeywordBool2 */ bool: $value); + +/* testReservedKeywordString1 */ +foobar(string: $value, /* testReservedKeywordString2 */ string: $value); + +/* testReservedKeywordTrue1 */ +foobar(true: $value, /* testReservedKeywordTrue2 */ true: $value); + +/* testReservedKeywordFalse1 */ +foobar(false: $value, /* testReservedKeywordFalse2 */ false: $value); + +/* testReservedKeywordNull1 */ +foobar(null: $value, /* testReservedKeywordNull2 */ null: $value); + +/* testReservedKeywordVoid1 */ +foobar(void: $value, /* testReservedKeywordVoid2 */ void: $value); + +/* testReservedKeywordIterable1 */ +foobar(iterable: $value, /* testReservedKeywordIterable2 */ iterable: $value); + +/* testReservedKeywordObject1 */ +foobar(object: $value, /* testReservedKeywordObject2 */ object: $value); + +/* testReservedKeywordResource1 */ +foobar(resource: $value, /* testReservedKeywordResource2 */ resource: $value); + +/* testReservedKeywordMixed1 */ +foobar(mixed: $value, /* testReservedKeywordMixed2 */ mixed: $value); + +/* testReservedKeywordNumeric1 */ +foobar(numeric: $value, /* testReservedKeywordNumeric2 */ numeric: $value); + +/* testReservedKeywordParent1 */ +foobar(parent: $value, /* testReservedKeywordParent2 */ parent: $value); + +/* testReservedKeywordSelf1 */ +foobar(self: $value, /* testReservedKeywordSelf2 */ self: $value); + +/* testReservedKeywordNever1 */ +foobar(never: $value, /* testReservedKeywordNever2 */ never: $value); diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.php new file mode 100644 index 00000000..768e41a9 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.php @@ -0,0 +1,974 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class NamedFunctionCallArgumentsTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that parameter labels are tokenized as T_PARAM_NAME and that + * the colon after it is tokenized as a T_COLON. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $parameters The token content for each parameter label to look for. + * + * @dataProvider dataNamedFunctionCallArguments + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNamedFunctionCallArguments($testMarker, $parameters) + { + $tokens = $this->phpcsFile->getTokens(); + + foreach ($parameters as $content) { + $label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content); + + $this->assertSame( + T_PARAM_NAME, + $tokens[$label]['code'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (code)' + ); + $this->assertSame( + 'T_PARAM_NAME', + $tokens[$label]['type'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (type)' + ); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + }//end foreach + + }//end testNamedFunctionCallArguments() + + + /** + * Data provider. + * + * @see testNamedFunctionCallArguments() + * + * @return array>> + */ + public static function dataNamedFunctionCallArguments() + { + return [ + 'function call, single line, all named args' => [ + 'testMarker' => '/* testNamedArgs */', + 'parameters' => [ + 'start_index', + 'count', + 'value', + ], + ], + 'function call, multi-line, all named args' => [ + 'testMarker' => '/* testNamedArgsMultiline */', + 'parameters' => [ + 'start_index', + 'count', + 'value', + ], + ], + 'function call, single line, all named args; comments and whitespace' => [ + 'testMarker' => '/* testNamedArgsWithWhitespaceAndComments */', + 'parameters' => [ + 'start_index', + 'count', + 'value', + ], + ], + 'function call, single line, mixed positional and named args' => [ + 'testMarker' => '/* testMixedPositionalAndNamedArgs */', + 'parameters' => [ + 'double_encode', + ], + ], + 'function call containing nested function call values' => [ + 'testMarker' => '/* testNestedFunctionCallOuter */', + 'parameters' => [ + 'start_index', + 'count', + 'value', + ], + ], + 'function call nested in named arg [1]' => [ + 'testMarker' => '/* testNestedFunctionCallInner1 */', + 'parameters' => [ + 'skip', + ], + ], + 'function call nested in named arg [2]' => [ + 'testMarker' => '/* testNestedFunctionCallInner2 */', + 'parameters' => [ + 'array_or_countable', + ], + ], + 'namespace relative function call' => [ + 'testMarker' => '/* testNamespaceRelativeFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'partially qualified function call' => [ + 'testMarker' => '/* testPartiallyQualifiedFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'fully qualified function call' => [ + 'testMarker' => '/* testFullyQualifiedFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'variable function call' => [ + 'testMarker' => '/* testVariableFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'variable variable function call' => [ + 'testMarker' => '/* testVariableVariableFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'method call' => [ + 'testMarker' => '/* testMethodCall */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'variable method call' => [ + 'testMarker' => '/* testVariableMethodCall */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'class instantiation' => [ + 'testMarker' => '/* testClassInstantiation */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'class instantiation with "self"' => [ + 'testMarker' => '/* testClassInstantiationSelf */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'class instantiation with "static"' => [ + 'testMarker' => '/* testClassInstantiationStatic */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'anonymous class instantiation' => [ + 'testMarker' => '/* testAnonClass */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'function call with non-ascii characters in the variable name labels' => [ + 'testMarker' => '/* testNonAsciiNames */', + 'parameters' => [ + '💩💩💩', + 'Пасха', + '_valid', + ], + ], + + // Coding errors which should still be handled. + 'invalid: named arg before positional (compile error)' => [ + 'testMarker' => '/* testCompileErrorNamedBeforePositional */', + 'parameters' => [ + 'param', + ], + ], + 'invalid: duplicate parameter name [1]' => [ + 'testMarker' => '/* testDuplicateName1 */', + 'parameters' => [ + 'param', + ], + ], + 'invalid: duplicate parameter name [2]' => [ + 'testMarker' => '/* testDuplicateName2 */', + 'parameters' => [ + 'param', + ], + ], + 'invalid: named arg before variadic (error exception)' => [ + 'testMarker' => '/* testIncorrectOrderWithVariadic */', + 'parameters' => [ + 'start_index', + ], + ], + 'invalid: named arg after variadic (compile error)' => [ + 'testMarker' => '/* testCompileErrorIncorrectOrderWithVariadic */', + 'parameters' => [ + 'param', + ], + ], + 'invalid: named arg without value (parse error)' => [ + 'testMarker' => '/* testParseErrorNoValue */', + 'parameters' => [ + 'param1', + 'param2', + ], + ], + 'invalid: named arg in exit() (parse error)' => [ + 'testMarker' => '/* testParseErrorExit */', + 'parameters' => [ + 'status', + ], + ], + 'invalid: named arg in empty() (parse error)' => [ + 'testMarker' => '/* testParseErrorEmpty */', + 'parameters' => [ + 'variable', + ], + ], + 'invalid: named arg in eval() (parse error)' => [ + 'testMarker' => '/* testParseErrorEval */', + 'parameters' => [ + 'code', + ], + ], + 'invalid: named arg in arbitrary parentheses (parse error)' => [ + 'testMarker' => '/* testParseErrorArbitraryParentheses */', + 'parameters' => [ + 'something', + ], + ], + ]; + + }//end dataNamedFunctionCallArguments() + + + /** + * Verify that other T_STRING tokens within a function call are still tokenized as T_STRING. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $content The token content to look for. + * + * @dataProvider dataOtherTstringInFunctionCall + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testOtherTstringInFunctionCall($testMarker, $content) + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content); + + $this->assertSame( + T_STRING, + $tokens[$label]['code'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_STRING (code)' + ); + $this->assertSame( + 'T_STRING', + $tokens[$label]['type'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_STRING (type)' + ); + + }//end testOtherTstringInFunctionCall() + + + /** + * Data provider. + * + * @see testOtherTstringInFunctionCall() + * + * @return array> + */ + public static function dataOtherTstringInFunctionCall() + { + return [ + 'not arg name - global constant' => [ + 'testMarker' => '/* testPositionalArgs */', + 'content' => 'START_INDEX', + ], + 'not arg name - fully qualified constant' => [ + 'testMarker' => '/* testPositionalArgs */', + 'content' => 'COUNT', + ], + 'not arg name - namespace relative constant' => [ + 'testMarker' => '/* testPositionalArgs */', + 'content' => 'VALUE', + ], + 'not arg name - unqualified function call' => [ + 'testMarker' => '/* testNestedFunctionCallInner2 */', + 'content' => 'count', + ], + ]; + + }//end dataOtherTstringInFunctionCall() + + + /** + * Verify whether the colons are tokenized correctly when a ternary is used in a mixed + * positional and named arguments function call. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testMixedPositionalAndNamedArgsWithTernary() + { + $tokens = $this->phpcsFile->getTokens(); + + $true = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_TRUE); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + $label = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_PARAM_NAME, 'name'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testMixedPositionalAndNamedArgsWithTernary() + + + /** + * Verify whether the colons are tokenized correctly when a ternary is used + * in a named arguments function call. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNamedArgWithTernary() + { + $tokens = $this->phpcsFile->getTokens(); + + /* + * First argument. + */ + + $label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'label'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'First arg: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'First arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'First arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $true = $this->getTargetToken('/* testNamedArgWithTernary */', T_TRUE); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'First arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'First arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + /* + * Second argument. + */ + + $label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'more'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Second arg: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Second arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Second arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $true = $this->getTargetToken('/* testNamedArgWithTernary */', T_STRING, 'CONSTANT_A'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'Second arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'Second arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + }//end testNamedArgWithTernary() + + + /** + * Verify whether the colons are tokenized correctly when named arguments + * function calls are used in a ternary. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTernaryWithFunctionCallsInThenElse() + { + $tokens = $this->phpcsFile->getTokens(); + + /* + * Then. + */ + + $label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'label'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Function in then: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Function in then: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Function in then: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $closeParens = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_CLOSE_PARENTHESIS); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($closeParens + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + /* + * Else. + */ + + $label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'more'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Function in else: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Function in else: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Function in else: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testTernaryWithFunctionCallsInThenElse() + + + /** + * Verify whether the colons are tokenized correctly when constants are used in a ternary. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTernaryWithConstantsInThenElse() + { + $tokens = $this->phpcsFile->getTokens(); + + $constant = $this->getTargetToken('/* testTernaryWithConstantsInThenElse */', T_STRING, 'CONSTANT_NAME'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($constant + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + }//end testTernaryWithConstantsInThenElse() + + + /** + * Verify whether the colons are tokenized correctly in a switch statement. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testSwitchStatement() + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken('/* testSwitchCaseWithConstant */', T_STRING, 'MY_CONSTANT'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'First case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'First case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $label = $this->getTargetToken('/* testSwitchCaseWithClassProperty */', T_STRING, 'property'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Second case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Second case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $default = $this->getTargetToken('/* testSwitchDefault */', T_DEFAULT); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($default + 1), null, true); + + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Default case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Default case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testSwitchStatement() + + + /** + * Verify that a variable parameter label (parse error) is still tokenized as T_VARIABLE. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testParseErrorVariableLabel() + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken('/* testParseErrorDynamicName */', [T_VARIABLE, T_PARAM_NAME], '$variableStoringParamName'); + + $this->assertSame( + T_VARIABLE, + $tokens[$label]['code'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_VARIABLE (code)' + ); + $this->assertSame( + 'T_VARIABLE', + $tokens[$label]['type'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_VARIABLE (type)' + ); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testParseErrorVariableLabel() + + + /** + * Verify whether the colons are tokenized correctly when a return type is used for an inline + * closure/arrow function declaration in a ternary. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataOtherColonsInTernary + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testOtherColonsInTernary($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $startOfStatement = $this->getTargetToken($testMarker, T_VARIABLE); + + // Walk the statement and check the tokenization. + // There should be no T_PARAM_NAME tokens. + // First colon should be T_COLON for the return type. + // Second colon should be T_INLINE_ELSE for the ternary. + // Third colon should be T_COLON for the return type. + $colonCount = 0; + for ($i = ($startOfStatement + 1); $tokens[$i]['line'] === $tokens[$startOfStatement]['line']; $i++) { + $this->assertNotSame(T_PARAM_NAME, $tokens[$i]['code'], "Token $i is tokenized as parameter label"); + + if ($tokens[$i]['content'] === ':') { + ++$colonCount; + + if ($colonCount === 1) { + $this->assertSame(T_COLON, $tokens[$i]['code'], 'First colon is not tokenized as T_COLON'); + } else if ($colonCount === 2) { + $this->assertSame(T_INLINE_ELSE, $tokens[$i]['code'], 'Second colon is not tokenized as T_INLINE_ELSE'); + } else if ($colonCount === 3) { + $this->assertSame(T_COLON, $tokens[$i]['code'], 'Third colon is not tokenized as T_COLON'); + } else { + $this->fail('Unexpected colon encountered in statement'); + } + } + } + + }//end testOtherColonsInTernary() + + + /** + * Data provider. + * + * @see testOtherColonsInTernary() + * + * @return array> + */ + public static function dataOtherColonsInTernary() + { + return [ + 'closures with return types in ternary' => [ + 'testMarker' => '/* testTernaryWithClosuresAndReturnTypes */', + ], + 'arrow functions with return types in ternary' => [ + 'testMarker' => '/* testTernaryWithArrowFunctionsAndReturnTypes */', + ], + ]; + + }//end dataOtherColonsInTernary() + + + /** + * Verify that reserved keywords used as a parameter label are tokenized as T_PARAM_NAME + * and that the colon after it is tokenized as a T_COLON. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $tokenTypes The token codes to look for. + * @param string $tokenContent The token content to look for. + * + * @dataProvider dataReservedKeywordsAsName + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testReservedKeywordsAsName($testMarker, $tokenTypes, $tokenContent) + { + $tokens = $this->phpcsFile->getTokens(); + $label = $this->getTargetToken($testMarker, $tokenTypes, $tokenContent); + + $this->assertSame( + T_PARAM_NAME, + $tokens[$label]['code'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (code)' + ); + $this->assertSame( + 'T_PARAM_NAME', + $tokens[$label]['type'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (type)' + ); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testReservedKeywordsAsName() + + + /** + * Data provider. + * + * @see testReservedKeywordsAsName() + * + * @return array>> + */ + public static function dataReservedKeywordsAsName() + { + $reservedKeywords = [ + // '__halt_compiler', NOT TESTABLE + 'abstract', + 'and', + 'array', + 'as', + 'break', + 'callable', + 'case', + 'catch', + 'class', + 'clone', + 'const', + 'continue', + 'declare', + 'default', + 'die', + 'do', + 'echo', + 'else', + 'elseif', + 'empty', + 'enddeclare', + 'endfor', + 'endforeach', + 'endif', + 'endswitch', + 'endwhile', + 'enum', + 'eval', + 'exit', + 'extends', + 'final', + 'finally', + 'fn', + 'for', + 'foreach', + 'function', + 'global', + 'goto', + 'if', + 'implements', + 'include', + 'include_once', + 'instanceof', + 'insteadof', + 'interface', + 'isset', + 'list', + 'match', + 'namespace', + 'new', + 'or', + 'print', + 'private', + 'protected', + 'public', + 'readonly', + 'require', + 'require_once', + 'return', + 'static', + 'switch', + 'throw', + 'trait', + 'try', + 'unset', + 'use', + 'var', + 'while', + 'xor', + 'yield', + 'int', + 'float', + 'bool', + 'string', + 'true', + 'false', + 'null', + 'void', + 'iterable', + 'object', + 'resource', + 'mixed', + 'numeric', + 'never', + + // Not reserved keyword, but do have their own token in PHPCS. + 'parent', + 'self', + ]; + + $data = []; + + foreach ($reservedKeywords as $keyword) { + $tokensTypes = [ + T_PARAM_NAME, + T_STRING, + T_GOTO_LABEL, + ]; + $tokenName = 'T_'.strtoupper($keyword); + + if ($keyword === 'and') { + $tokensTypes[] = T_LOGICAL_AND; + } else if ($keyword === 'die') { + $tokensTypes[] = T_EXIT; + } else if ($keyword === 'or') { + $tokensTypes[] = T_LOGICAL_OR; + } else if ($keyword === 'xor') { + $tokensTypes[] = T_LOGICAL_XOR; + } else if ($keyword === '__halt_compiler') { + $tokensTypes[] = T_HALT_COMPILER; + } else if (defined($tokenName) === true) { + $tokensTypes[] = constant($tokenName); + } + + $data[$keyword.'FirstParam'] = [ + '/* testReservedKeyword'.ucfirst($keyword).'1 */', + $tokensTypes, + $keyword, + ]; + + $data[$keyword.'SecondParam'] = [ + '/* testReservedKeyword'.ucfirst($keyword).'2 */', + $tokensTypes, + $keyword, + ]; + }//end foreach + + return $data; + + }//end dataReservedKeywordsAsName() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullableVsInlineThenTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullableVsInlineThenTest.inc new file mode 100644 index 00000000..56ad3856 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullableVsInlineThenTest.inc @@ -0,0 +1,19 @@ +phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_NULLABLE, T_INLINE_THEN]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_NULLABLE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_NULLABLE (code)'); + $this->assertSame('T_NULLABLE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_NULLABLE (type)'); + + }//end testNullable() + + + /** + * Data provider. + * + * @see testNullable() + * + * @return array> + */ + public static function dataNullable() + { + return [ + 'property declaration, readonly, no visibility' => ['/* testNullableReadonlyOnly */'], + 'property declaration, private set' => ['/* testNullablePrivateSet */'], + 'property declaration, public and protected set' => ['/* testNullablePublicProtectedSet */'], + ]; + + }//end dataNullable() + + + /** + * Test that "readonly" when not used as the keyword is still tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataInlineThen + * + * @return void + */ + public function testInlineThen($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_NULLABLE, T_INLINE_THEN]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_INLINE_THEN, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_INLINE_THEN (code)'); + $this->assertSame('T_INLINE_THEN', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_INLINE_THEN (type)'); + + }//end testInlineThen() + + + /** + * Data provider. + * + * @see testInlineThen() + * + * @return array> + */ + public static function dataInlineThen() + { + return [ + 'ternary in property default value' => ['/* testInlineThenInPropertyDefaultValue */'], + ]; + + }//end dataInlineThen() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.inc new file mode 100644 index 00000000..982841ea --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.inc @@ -0,0 +1,29 @@ +foo; + +/* testNullsafeObjectOperator */ +echo $obj?->foo; + +/* testNullsafeObjectOperatorWriteContext */ +// Intentional parse error, but not the concern of the tokenizer. +$foo?->bar->baz = 'baz'; + +/* testTernaryThen */ +echo $obj ? $obj->prop : $other->prop; + +/* testParseErrorWhitespaceNotAllowed */ +echo $obj ? + -> foo; + +/* testParseErrorCommentNotAllowed */ +echo $obj ?/*comment*/-> foo; + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +echo $obj? diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.php new file mode 100644 index 00000000..368fee4d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.php @@ -0,0 +1,144 @@ += 8.0 nullsafe object operator. + * + * @author Juliette Reinders Folmer + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class NullsafeObjectOperatorTest extends AbstractTokenizerTestCase +{ + + /** + * Tokens to search for. + * + * @var array + */ + protected $find = [ + T_NULLSAFE_OBJECT_OPERATOR, + T_OBJECT_OPERATOR, + T_INLINE_THEN, + ]; + + + /** + * Test that a normal object operator is still tokenized as such. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testObjectOperator() + { + $tokens = $this->phpcsFile->getTokens(); + + $operator = $this->getTargetToken('/* testObjectOperator */', $this->find); + $this->assertSame(T_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is object operator'); + $this->assertSame('T_OBJECT_OPERATOR', $tokens[$operator]['type'], 'Failed asserting type is object operator'); + + }//end testObjectOperator() + + + /** + * Test that a nullsafe object operator is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataNullsafeObjectOperator + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNullsafeObjectOperator($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $operator = $this->getTargetToken($testMarker, $this->find); + $this->assertSame(T_NULLSAFE_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is nullsafe object operator'); + $this->assertSame('T_NULLSAFE_OBJECT_OPERATOR', $tokens[$operator]['type'], 'Failed asserting type is nullsafe object operator'); + + }//end testNullsafeObjectOperator() + + + /** + * Data provider. + * + * @see testNullsafeObjectOperator() + * + * @return array> + */ + public static function dataNullsafeObjectOperator() + { + return [ + 'nullsafe operator' => ['/* testNullsafeObjectOperator */'], + 'illegal nullsafe operator (write context)' => ['/* testNullsafeObjectOperatorWriteContext */'], + ]; + + }//end dataNullsafeObjectOperator() + + + /** + * Test that a question mark not followed by an object operator is tokenized as T_TERNARY_THEN. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $testObjectOperator Whether to test for the next non-empty token being tokenized + * as an object operator. + * + * @dataProvider dataTernaryThen + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTernaryThen($testMarker, $testObjectOperator=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $operator = $this->getTargetToken($testMarker, $this->find); + $this->assertSame(T_INLINE_THEN, $tokens[$operator]['code'], 'Failed asserting code is inline then'); + $this->assertSame('T_INLINE_THEN', $tokens[$operator]['type'], 'Failed asserting type is inline then'); + + if ($testObjectOperator === true) { + $next = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($operator + 1), null, true); + $this->assertSame(T_OBJECT_OPERATOR, $tokens[$next]['code'], 'Failed asserting code is object operator'); + $this->assertSame('T_OBJECT_OPERATOR', $tokens[$next]['type'], 'Failed asserting type is object operator'); + } + + }//end testTernaryThen() + + + /** + * Data provider. + * + * @see testTernaryThen() + * + * @return array> + */ + public static function dataTernaryThen() + { + return [ + 'ternary then' => [ + 'testMarker' => '/* testTernaryThen */', + ], + 'whitespace between question mark and object operator' => [ + 'testMarker' => '/* testParseErrorWhitespaceNotAllowed */', + 'testObjectOperator' => true, + ], + 'comment between question mark and object operator' => [ + 'testMarker' => '/* testParseErrorCommentNotAllowed */', + 'testObjectOperator' => true, + ], + 'parse error/live coding' => [ + 'testMarker' => '/* testLiveCoding */', + ], + ]; + + }//end dataTernaryThen() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.inc new file mode 100644 index 00000000..028592f7 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.inc @@ -0,0 +1,247 @@ + $param->get(); + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.php new file mode 100644 index 00000000..35c89971 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.php @@ -0,0 +1,721 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the conversion of PHPCS native context sensitive keyword tokens to T_STRING. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::standardiseToken + */ +final class OtherContextSensitiveKeywordsTest extends AbstractTokenizerTestCase +{ + + + /** + * Clear the "resolved tokens" cache before running this test as otherwise the code + * under test may not be run during the test. + * + * @beforeClass + * + * @return void + */ + public static function clearTokenCache() + { + parent::clearResolvedTokensCache(); + + }//end clearTokenCache() + + + /** + * Test that context sensitive keyword is tokenized as string when it should be string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataStrings + * + * @return void + */ + public function testStrings($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testStrings() + + + /** + * Data provider. + * + * @see testStrings() + * + * @return array> + */ + public static function dataStrings() + { + return [ + 'constant declaration: parent' => ['/* testParent */'], + 'constant declaration: self' => ['/* testSelf */'], + 'constant declaration: false' => ['/* testFalse */'], + 'constant declaration: true' => ['/* testTrue */'], + 'constant declaration: null' => ['/* testNull */'], + + 'function declaration with return by ref: self' => ['/* testKeywordSelfAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: parent' => ['/* testKeywordParentAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: false' => ['/* testKeywordFalseAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: true' => ['/* testKeywordTrueAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: null' => ['/* testKeywordNullAfterFunctionByRefShouldBeString */'], + + 'function call: self' => ['/* testKeywordAsFunctionCallNameShouldBeStringSelf */'], + 'function call: parent' => ['/* testKeywordAsFunctionCallNameShouldBeStringParent */'], + 'function call: false' => ['/* testKeywordAsFunctionCallNameShouldBeStringFalse */'], + 'function call: true' => ['/* testKeywordAsFunctionCallNameShouldBeStringTrue */'], + 'function call: null; with comment between keyword and parentheses' => ['/* testKeywordAsFunctionCallNameShouldBeStringNull */'], + + 'class instantiation: false' => ['/* testClassInstantiationFalseIsString */'], + 'class instantiation: true' => ['/* testClassInstantiationTrueIsString */'], + 'class instantiation: null' => ['/* testClassInstantiationNullIsString */'], + + 'constant declaration: false as name after type' => ['/* testFalseIsNameForTypedConstant */'], + 'constant declaration: true as name after type' => ['/* testTrueIsNameForTypedConstant */'], + 'constant declaration: null as name after type' => ['/* testNullIsNameForTypedConstant */'], + 'constant declaration: self as name after type' => ['/* testSelfIsNameForTypedConstant */'], + 'constant declaration: parent as name after type' => ['/* testParentIsNameForTypedConstant */'], + ]; + + }//end dataStrings() + + + /** + * Test that context sensitive keyword is tokenized as keyword when it should be keyword. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedTokenType The expected token type. + * + * @dataProvider dataKeywords + * + * @return void + */ + public function testKeywords($testMarker, $expectedTokenType) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); + $tokenArray = $tokens[$target]; + + $this->assertSame( + constant($expectedTokenType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (code)' + ); + $this->assertSame( + $expectedTokenType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (type)' + ); + + }//end testKeywords() + + + /** + * Data provider. + * + * @see testKeywords() + * + * @return array> + */ + public static function dataKeywords() + { + return [ + 'self: param type declaration' => [ + 'testMarker' => '/* testSelfIsKeyword */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: param type declaration' => [ + 'testMarker' => '/* testParentIsKeyword */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'parent: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationParentIsKeyword */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationSelfIsKeyword */', + 'expectedTokenType' => 'T_SELF', + ], + + 'false: param type declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: param type declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: param type declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamType */', + 'expectedTokenType' => 'T_NULL', + ], + 'false: return type declaration in union' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: return type declaration in union' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: return type declaration in union' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_NULL', + ], + 'false: in comparison' => [ + 'testMarker' => '/* testFalseIsKeywordInComparison */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: in comparison' => [ + 'testMarker' => '/* testTrueIsKeywordInComparison */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: in comparison' => [ + 'testMarker' => '/* testNullIsKeywordInComparison */', + 'expectedTokenType' => 'T_NULL', + ], + + 'false: type in OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: type in OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: type in OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: type in OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: type in OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: value in constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: value in constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: value in constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: value in constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: value in constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: type in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: type in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: type in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: type in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: type in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: value in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: value in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: value in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: value in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: value in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: DNF type in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: DNF type in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: DNF type in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: DNF type in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: DNF type in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: DNF type in function param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'false: DNF type in function return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: DNF type in function param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'true: DNF type in function return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: DNF type in function param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'null: DNF type in function return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: DNF type in function param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'self: DNF type in function return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: DNF type in function param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + 'parent: DNF type in function return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + + ]; + + }//end dataKeywords() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF1Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF1Test.inc new file mode 100644 index 00000000..2244b389 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF1Test.inc @@ -0,0 +1,4 @@ + +phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken('/* testLongOpenTagEndOfFileSpaceNoNewLine */', [T_OPEN_TAG, T_STRING, T_INLINE_HTML]); + + $this->assertSame( + T_OPEN_TAG, + $tokens[$stackPtr]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$stackPtr]['code']).', not T_OPEN_TAG (code)' + ); + $this->assertSame( + 'T_OPEN_TAG', + $tokens[$stackPtr]['type'], + 'Token tokenized as '.$tokens[$stackPtr]['type'].', not T_OPEN_TAG (type)' + ); + $this->assertSame('assertArrayNotHasKey(($stackPtr + 1), $tokens); + + }//end testLongOpenTagAtEndOfFile() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF2Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF2Test.inc new file mode 100644 index 00000000..191bdae1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF2Test.inc @@ -0,0 +1,4 @@ + +phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken('/* testLongOpenTagEndOfFileNoSpaceNoNewLine */', [T_OPEN_TAG, T_STRING, T_INLINE_HTML]); + + $this->assertSame( + T_OPEN_TAG, + $tokens[$stackPtr]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$stackPtr]['code']).', not T_OPEN_TAG (code)' + ); + $this->assertSame( + 'T_OPEN_TAG', + $tokens[$stackPtr]['type'], + 'Token tokenized as '.$tokens[$stackPtr]['type'].', not T_OPEN_TAG (type)' + ); + $this->assertSame('assertArrayNotHasKey(($stackPtr + 1), $tokens); + + }//end testLongOpenTagAtEndOfFile() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF3Test.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF3Test.inc new file mode 100644 index 00000000..583314db --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF3Test.inc @@ -0,0 +1,4 @@ + +phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken('/* testLongOpenTagEndOfFileNoSpaceNoNewLineUppercase */', [T_OPEN_TAG, T_STRING, T_INLINE_HTML]); + + $this->assertSame( + T_OPEN_TAG, + $tokens[$stackPtr]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$stackPtr]['code']).', not T_OPEN_TAG (code)' + ); + $this->assertSame( + 'T_OPEN_TAG', + $tokens[$stackPtr]['type'], + 'Token tokenized as '.$tokens[$stackPtr]['type'].', not T_OPEN_TAG (type)' + ); + $this->assertSame('assertArrayNotHasKey(($stackPtr + 1), $tokens); + + }//end testLongOpenTagAtEndOfFile() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.inc new file mode 100644 index 00000000..d7383d8e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.inc @@ -0,0 +1,51 @@ + $var; + +/* testBooleanNot */ +$a = ! $var; + +/* testComma */ +echo $a, $b, $c; + +/* testAsperand */ +$a = @callMe(); + +/* testDollarAndCurlies */ +echo ${$var}; + +/* testBacktick */ +$a = `ls -e`; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.php new file mode 100644 index 00000000..06a130c2 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.php @@ -0,0 +1,433 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests that simple tokens are assigned the correct token type and code. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::resolveSimpleToken + */ +final class ResolveSimpleTokenTest extends AbstractTokenizerTestCase +{ + + + /** + * Clear the "resolved tokens" cache before running this test as otherwise the code + * under test may not be run during the test. + * + * @beforeClass + * + * @return void + */ + public static function clearTokenCache() + { + parent::clearResolvedTokensCache(); + + }//end clearTokenCache() + + + /** + * Verify tokenization of parentheses, square brackets, curly brackets and a switch colon. + * + * @return void + */ + public function testBracesAndColon() + { + $expectedSequence = [ + T_OPEN_PARENTHESIS, + T_VARIABLE, + T_OPEN_SQUARE_BRACKET, + T_LNUMBER, + T_CLOSE_SQUARE_BRACKET, + T_CLOSE_PARENTHESIS, + T_OPEN_CURLY_BRACKET, + T_CASE, + T_STRING, + T_COLON, + T_BREAK, + T_SEMICOLON, + T_CLOSE_CURLY_BRACKET, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_SWITCH); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBracesAndColon() + + + /** + * Verify tokenization of colon after named parameter. + * + * @return void + */ + public function testNamedParamColon() + { + $expectedSequence = [ + T_OPEN_PARENTHESIS, + T_PARAM_NAME, + T_COLON, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_STRING); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testNamedParamColon() + + + /** + * Verify tokenization of colon for a return type. + * + * @return void + */ + public function testReturnTypeColon() + { + $expectedSequence = [ + T_EQUAL, + T_CLOSURE, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_COLON, + T_STRING, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testReturnTypeColon() + + + /** + * Verify tokenization of a concatenation operator. + * + * @return void + */ + public function testConcat() + { + $expectedSequence = [ + T_STRING_CONCAT, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_CONSTANT_ENCAPSED_STRING); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testConcat() + + + /** + * Verify tokenization of simple math operators. + * + * @return void + */ + public function testSimpleMathTokens() + { + $expectedSequence = [ + T_EQUAL, + T_LNUMBER, + T_MULTIPLY, + T_LNUMBER, + T_DIVIDE, + T_LNUMBER, + T_PLUS, + T_LNUMBER, + T_MINUS, + T_LNUMBER, + T_MODULUS, + T_LNUMBER, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testSimpleMathTokens() + + + /** + * Verify tokenization of unary plus/minus operators. + * + * @return void + */ + public function testUnaryPlusMinus() + { + $expectedSequence = [ + T_EQUAL, + T_PLUS, + T_LNUMBER, + T_DIVIDE, + T_MINUS, + T_LNUMBER, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testUnaryPlusMinus() + + + /** + * Verify tokenization of bitwise operator tokens. + * + * @return void + */ + public function testBitwiseTokens() + { + $expectedSequence = [ + T_EQUAL, + T_STRING, + T_BITWISE_XOR, + T_STRING, + T_BITWISE_AND, + T_STRING, + T_BITWISE_OR, + T_STRING, + T_BITWISE_NOT, + T_STRING, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBitwiseTokens() + + + /** + * Verify tokenization of bitwise operator tokens. + * + * @return void + */ + public function testBitwiseOrInCatch() + { + $expectedSequence = [ + T_OPEN_PARENTHESIS, + T_STRING, + T_BITWISE_OR, + T_STRING, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_CATCH); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBitwiseOrInCatch() + + + /** + * Verify tokenization of a less than operator. + * + * @return void + */ + public function testLessThan() + { + $expectedSequence = [ + T_LESS_THAN, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_LNUMBER); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testLessThan() + + + /** + * Verify tokenization of a greater than operator. + * + * @return void + */ + public function testGreaterThan() + { + $expectedSequence = [ + T_GREATER_THAN, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_LNUMBER); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testGreaterThan() + + + /** + * Verify tokenization of a boolean not operator. + * + * @return void + */ + public function testBooleanNot() + { + $expectedSequence = [ + T_BOOLEAN_NOT, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBooleanNot() + + + /** + * Verify tokenization of commas. + * + * @return void + */ + public function testComma() + { + $expectedSequence = [ + T_COMMA, + T_VARIABLE, + T_COMMA, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testComma() + + + /** + * Verify tokenization of the silence operator. + * + * @return void + */ + public function testAsperand() + { + $expectedSequence = [ + T_ASPERAND, + T_STRING, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testAsperand() + + + /** + * Verify tokenization of the dollar token and curlies for a variable variable. + * + * @return void + */ + public function testDollarAndCurlies() + { + $expectedSequence = [ + T_DOLLAR, + T_OPEN_CURLY_BRACKET, + T_VARIABLE, + T_CLOSE_CURLY_BRACKET, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_ECHO); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testDollarAndCurlies() + + + /** + * Verify tokenization of the backtick operator. + * + * @return void + */ + public function testBacktick() + { + $expectedSequence = [ + T_BACKTICK, + T_ENCAPSED_AND_WHITESPACE, + T_BACKTICK, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBacktick() + + + /** + * Test helper. Check a token sequence complies with an expected token sequence. + * + * @param int $startPtr The position in the file to start checking from. + * @param array $expectedSequence The consecutive token constants to expect. + * + * @return void + */ + private function checkTokenSequence($startPtr, array $expectedSequence) + { + $tokens = $this->phpcsFile->getTokens(); + + $sequenceKey = 0; + $sequenceCount = count($expectedSequence); + + for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + // Ignore whitespace and comments, not interested in the tokenization of those for these tests. + continue; + } + + $expectedTokenName = Tokens::tokenName($expectedSequence[$sequenceKey]); + + $this->assertSame( + $expectedSequence[$sequenceKey], + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedTokenName.' (code)' + ); + + $this->assertSame( + $expectedTokenName, + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedTokenName.' (type)' + ); + + ++$sequenceKey; + }//end for + + }//end checkTokenSequence() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.inc new file mode 100644 index 00000000..60b23a51 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.inc @@ -0,0 +1,111 @@ +function_call()[$x]; + +/* testStaticMethodCallDereferencing */ +$var = ClassName::function_call()[$x]; + +/* testPropertyDereferencing */ +$var = $obj->property[2]; + +/* testPropertyDereferencingWithInaccessibleName */ +$var = $ref->{'ref-type'}[1]; + +/* testStaticPropertyDereferencing */ +$var ClassName::$property[2]; + +/* testStringDereferencing */ +$var = 'PHP'[1]; + +/* testStringDereferencingDoubleQuoted */ +$var = "PHP"[$y]; + +/* testConstantDereferencing */ +$var = MY_CONSTANT[1]; + +/* testClassConstantDereferencing */ +$var ClassName::CONSTANT_NAME[2]; + +/* testMagicConstantDereferencing */ +$var = __FILE__[0]; + +/* testArrayAccessCurlyBraces */ +$var = $array{'key'}['key']; + +/* testArrayLiteralDereferencing */ +echo array(1, 2, 3)[0]; + +echo [1, 2, 3]/* testShortArrayLiteralDereferencing */[0]; + +/* testClassMemberDereferencingOnInstantiation1 */ +(new foo)[0]; + +/* testClassMemberDereferencingOnInstantiation2 */ +$a = (new Foo( array(1, array(4, 5), 3) ))[1][0]; + +/* testClassMemberDereferencingOnClone */ +echo (clone $iterable)[20]; + +/* testNullsafeMethodCallDereferencing */ +$var = $obj?->function_call()[$x]; + +/* testInterpolatedStringDereferencing */ +$var = "PHP{$rocks}"[1]; + +/* + * Short array brackets. + */ + +/* testShortArrayDeclarationEmpty */ +$array = []; + +/* testShortArrayDeclarationWithOneValue */ +$array = [1]; + +/* testShortArrayDeclarationWithMultipleValues */ +$array = [1, 2, 3]; + +/* testShortArrayDeclarationWithDereferencing */ +echo [1, 2, 3][0]; + +/* testShortListDeclaration */ +[ $a, $b ] = $array; + +[ $a, $b, /* testNestedListDeclaration */, [$c, $d]] = $array; + +/* testArrayWithinFunctionCall */ +$var = functionCall([$x, $y]); + +if ( true ) { + /* testShortListDeclarationAfterBracedControlStructure */ + [ $a ] = [ 'hi' ]; +} + +if ( true ) + /* testShortListDeclarationAfterNonBracedControlStructure */ + [ $a ] = [ 'hi' ]; + +if ( true ) : + /* testShortListDeclarationAfterAlternativeControlStructure */ + [ $a ] = [ 'hi' ]; +endif; + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$array = [ diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.php new file mode 100644 index 00000000..da9c7c10 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.php @@ -0,0 +1,141 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class ShortArrayTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that real square brackets are still tokenized as square brackets. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataSquareBrackets + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testSquareBrackets($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); + $tokenArray = $tokens[$opener]; + + $this->assertSame(T_OPEN_SQUARE_BRACKET, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SQUARE_BRACKET (code)'); + $this->assertSame('T_OPEN_SQUARE_BRACKET', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SQUARE_BRACKET (type)'); + + if (isset($tokens[$opener]['bracket_closer']) === true) { + $closer = $tokens[$opener]['bracket_closer']; + $tokenArray = $tokens[$closer]; + + $this->assertSame(T_CLOSE_SQUARE_BRACKET, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SQUARE_BRACKET (code)'); + $this->assertSame('T_CLOSE_SQUARE_BRACKET', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SQUARE_BRACKET (type)'); + } + + }//end testSquareBrackets() + + + /** + * Data provider. + * + * @see testSquareBrackets() + * + * @return array> + */ + public static function dataSquareBrackets() + { + return [ + 'array access 1' => ['/* testArrayAccess1 */'], + 'array access 2' => ['/* testArrayAccess2 */'], + 'array assignment' => ['/* testArrayAssignment */'], + 'function call dereferencing' => ['/* testFunctionCallDereferencing */'], + 'method call dereferencing' => ['/* testMethodCallDereferencing */'], + 'static method call dereferencing' => ['/* testStaticMethodCallDereferencing */'], + 'property dereferencing' => ['/* testPropertyDereferencing */'], + 'property dereferencing with inaccessable name' => ['/* testPropertyDereferencingWithInaccessibleName */'], + 'static property dereferencing' => ['/* testStaticPropertyDereferencing */'], + 'string dereferencing single quotes' => ['/* testStringDereferencing */'], + 'string dereferencing double quotes' => ['/* testStringDereferencingDoubleQuoted */'], + 'global constant dereferencing' => ['/* testConstantDereferencing */'], + 'class constant dereferencing' => ['/* testClassConstantDereferencing */'], + 'magic constant dereferencing' => ['/* testMagicConstantDereferencing */'], + 'array access with curly braces' => ['/* testArrayAccessCurlyBraces */'], + 'array literal dereferencing' => ['/* testArrayLiteralDereferencing */'], + 'short array literal dereferencing' => ['/* testShortArrayLiteralDereferencing */'], + 'class member dereferencing on instantiation 1' => ['/* testClassMemberDereferencingOnInstantiation1 */'], + 'class member dereferencing on instantiation 2' => ['/* testClassMemberDereferencingOnInstantiation2 */'], + 'class member dereferencing on clone' => ['/* testClassMemberDereferencingOnClone */'], + 'nullsafe method call dereferencing' => ['/* testNullsafeMethodCallDereferencing */'], + 'interpolated string dereferencing' => ['/* testInterpolatedStringDereferencing */'], + 'live coding' => ['/* testLiveCoding */'], + ]; + + }//end dataSquareBrackets() + + + /** + * Test that short arrays and short lists are still tokenized as short arrays. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataShortArrays + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testShortArrays($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); + $tokenArray = $tokens[$opener]; + + $this->assertSame(T_OPEN_SHORT_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SHORT_ARRAY (code)'); + $this->assertSame('T_OPEN_SHORT_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SHORT_ARRAY (type)'); + + if (isset($tokens[$opener]['bracket_closer']) === true) { + $closer = $tokens[$opener]['bracket_closer']; + $tokenArray = $tokens[$closer]; + + $this->assertSame(T_CLOSE_SHORT_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SHORT_ARRAY (code)'); + $this->assertSame('T_CLOSE_SHORT_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SHORT_ARRAY (type)'); + } + + }//end testShortArrays() + + + /** + * Data provider. + * + * @see testShortArrays() + * + * @return array> + */ + public static function dataShortArrays() + { + return [ + 'short array empty' => ['/* testShortArrayDeclarationEmpty */'], + 'short array with value' => ['/* testShortArrayDeclarationWithOneValue */'], + 'short array with values' => ['/* testShortArrayDeclarationWithMultipleValues */'], + 'short array with dereferencing' => ['/* testShortArrayDeclarationWithDereferencing */'], + 'short list' => ['/* testShortListDeclaration */'], + 'short list nested' => ['/* testNestedListDeclaration */'], + 'short array within function call' => ['/* testArrayWithinFunctionCall */'], + 'short list after braced control structure' => ['/* testShortListDeclarationAfterBracedControlStructure */'], + 'short list after non-braced control structure' => ['/* testShortListDeclarationAfterNonBracedControlStructure */'], + 'short list after alternative control structure' => ['/* testShortListDeclarationAfterAlternativeControlStructure */'], + ]; + + }//end dataShortArrays() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.inc new file mode 100644 index 00000000..3bf013c6 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.inc @@ -0,0 +1,139 @@ + + + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class StableCommentWhitespaceTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that comment tokenization with new lines at the end of the comment is stable. + * + * @param string $testMarker The comment prefacing the test. + * @param array> $expectedTokens The tokenization expected. + * + * @dataProvider dataCommentTokenization + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testCommentTokenization($testMarker, $expectedTokens) + { + $tokens = $this->phpcsFile->getTokens(); + $comment = $this->getTargetToken($testMarker, Tokens::$commentTokens); + + foreach ($expectedTokens as $tokenInfo) { + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$comment]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$comment]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$comment]['type'], + 'Token tokenized as '.$tokens[$comment]['type'].', not '.$tokenInfo['type'].' (type)' + ); + $this->assertSame($tokenInfo['content'], $tokens[$comment]['content']); + + ++$comment; + } + + }//end testCommentTokenization() + + + /** + * Data provider. + * + * @see testCommentTokenization() + * + * @return array>>> + */ + public static function dataCommentTokenization() + { + return [ + 'slash comment, single line' => [ + 'testMarker' => '/* testSingleLineSlashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineSlashCommentTrailing */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineSlashAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_PHPCS_DISABLE', + 'content' => '// phpcs:disable Stnd.Cat +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineSlashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithIndent */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, ignore annotation as first line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationStart */', + 'expectedTokens' => [ + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, ignore annotation as middle line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationMiddle */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// @phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, ignore annotation as last line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'star comment, single line' => [ + 'testMarker' => '/* testSingleLineStarComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '/* Single line star comment */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'star comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineStarCommentTrailing */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '/* Comment */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'star ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineStarAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '/* phpcs:ignore Stnd.Cat */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'star comment, multi-line' => [ + 'testMarker' => '/* testMultiLineStarComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '/* Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' * Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' * Comment3 */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'star comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineStarCommentWithIndent */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '/* Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' * Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' * Comment3 */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'star comment, multi-line, ignore annotation as first line' => [ + 'testMarker' => '/* testMultiLineStarCommentWithAnnotationStart */', + 'expectedTokens' => [ + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '/* @phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' * Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' * Comment3 */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'star comment, multi-line, ignore annotation as middle line' => [ + 'testMarker' => '/* testMultiLineStarCommentWithAnnotationMiddle */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '/* Comment1 +', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => ' * phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' * Comment3 */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'star comment, multi-line, ignore annotation as last line' => [ + 'testMarker' => '/* testMultiLineStarCommentWithAnnotationEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '/* Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' * Comment2 +', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => ' * phpcs:ignore Stnd.Cat */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + + 'docblock comment, single line' => [ + 'testMarker' => '/* testSingleLineDocblockComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_DOC_COMMENT_OPEN_TAG', + 'content' => '/**', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment ', + ], + [ + 'type' => 'T_DOC_COMMENT_CLOSE_TAG', + 'content' => '*/', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'docblock comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineDocblockCommentTrailing */', + 'expectedTokens' => [ + [ + 'type' => 'T_DOC_COMMENT_OPEN_TAG', + 'content' => '/**', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment ', + ], + [ + 'type' => 'T_DOC_COMMENT_CLOSE_TAG', + 'content' => '*/', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'docblock ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineDocblockAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_DOC_COMMENT_OPEN_TAG', + 'content' => '/**', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => 'phpcs:ignore Stnd.Cat.Sniff ', + ], + [ + 'type' => 'T_DOC_COMMENT_CLOSE_TAG', + 'content' => '*/', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + + 'docblock comment, multi-line' => [ + 'testMarker' => '/* testMultiLineDocblockComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_DOC_COMMENT_OPEN_TAG', + 'content' => '/**', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment1', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment2', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_TAG', + 'content' => '@tag', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_CLOSE_TAG', + 'content' => '*/', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'docblock comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineDocblockCommentWithIndent */', + 'expectedTokens' => [ + [ + 'type' => 'T_DOC_COMMENT_OPEN_TAG', + 'content' => '/**', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment1', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment2', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_TAG', + 'content' => '@tag', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_CLOSE_TAG', + 'content' => '*/', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'docblock comment, multi-line, ignore annotation' => [ + 'testMarker' => '/* testMultiLineDocblockCommentWithAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_DOC_COMMENT_OPEN_TAG', + 'content' => '/**', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => 'phpcs:ignore Stnd.Cat', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_TAG', + 'content' => '@tag', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_CLOSE_TAG', + 'content' => '*/', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'docblock comment, multi-line, ignore annotation as tag' => [ + 'testMarker' => '/* testMultiLineDocblockCommentWithTagAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_DOC_COMMENT_OPEN_TAG', + 'content' => '/**', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '@phpcs:ignore Stnd.Cat', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STAR', + 'content' => '*', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_TAG', + 'content' => '@tag', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_STRING', + 'content' => 'Comment', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_DOC_COMMENT_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_DOC_COMMENT_CLOSE_TAG', + 'content' => '*/', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, single line' => [ + 'testMarker' => '/* testSingleLineHashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineHashCommentTrailing */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineHashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineHashCommentWithIndent */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment1 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment2 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineSlashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Slash ', + ], + [ + 'type' => 'T_CLOSE_TAG', + 'content' => '?> +', + ], + ], + ], + 'hash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineHashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Hash ', + ], + [ + 'type' => 'T_CLOSE_TAG', + 'content' => '?> +', + ], + ], + ], + 'unclosed star comment at end of file' => [ + 'testMarker' => '/* testCommentAtEndOfFile */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '/* Comment', + ], + ], + ], + ]; + + }//end dataCommentTokenization() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.inc new file mode 100644 index 00000000..dc98eb01 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.inc @@ -0,0 +1,63 @@ + + + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class StableCommentWhitespaceWinTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that comment tokenization with new lines at the end of the comment is stable. + * + * @param string $testMarker The comment prefacing the test. + * @param array> $expectedTokens The tokenization expected. + * + * @dataProvider dataCommentTokenization + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testCommentTokenization($testMarker, $expectedTokens) + { + $tokens = $this->phpcsFile->getTokens(); + $comment = $this->getTargetToken($testMarker, Tokens::$commentTokens); + + foreach ($expectedTokens as $tokenInfo) { + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$comment]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$comment]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$comment]['type'], + 'Token tokenized as '.$tokens[$comment]['type'].', not '.$tokenInfo['type'].' (type)' + ); + $this->assertSame($tokenInfo['content'], $tokens[$comment]['content']); + + ++$comment; + } + + }//end testCommentTokenization() + + + /** + * Data provider. + * + * @see testCommentTokenization() + * + * @return array>>> + */ + public static function dataCommentTokenization() + { + return [ + 'slash comment, single line' => [ + 'testMarker' => '/* testSingleLineSlashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineSlashCommentTrailing */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineSlashAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_PHPCS_DISABLE', + 'content' => '// phpcs:disable Stnd.Cat +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineSlashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithIndent */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, ignore annotation as first line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationStart */', + 'expectedTokens' => [ + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, ignore annotation as middle line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationMiddle */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// @phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, ignore annotation as last line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineSlashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Slash ', + ], + [ + 'type' => 'T_CLOSE_TAG', + 'content' => '?> +', + ], + ], + ], + 'hash comment, single line' => [ + 'testMarker' => '/* testSingleLineHashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineHashCommentTrailing */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineHashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineHashCommentWithIndent */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment1 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment2 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineHashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Hash ', + ], + [ + 'type' => 'T_CLOSE_TAG', + 'content' => '?> +', + ], + ], + ], + 'unclosed star comment at end of file' => [ + 'testMarker' => '/* testCommentAtEndOfFile */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '/* Comment', + ], + ], + ], + ]; + + }//end dataCommentTokenization() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.inc new file mode 100644 index 00000000..54b3c06e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.inc @@ -0,0 +1,179 @@ + $param & $int; + +/* testTypeIntersectionArrowReturnType */ +$arrowWithReturnType = fn ($param) : Foo&Bar => $param * 10; + +/* testBitwiseAndInArrayKey */ +$array = array( + A & B => /* testBitwiseAndInArrayValue */ B & C +); + +/* testBitwiseAndInShortArrayKey */ +$array = [ + A & B => /* testBitwiseAndInShortArrayValue */ B & C +]; + +/* testBitwiseAndNonArrowFnFunctionCall */ +$obj->fn($something & $else); + +/* testBitwiseAnd6 */ +function &fn(/* testTypeIntersectionNonArrowFunctionDeclaration */ Foo&Bar $something) {} + +/* testTypeIntersectionWithInvalidTypes */ +function (int&string $var) {}; + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +return function( Foo& diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.php new file mode 100644 index 00000000..3a4eb007 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.php @@ -0,0 +1,163 @@ + + * @author Jaroslav Hanslík + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class TypeIntersectionTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that non-intersection type bitwise and tokens are still tokenized as bitwise and. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataBitwiseAnd + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBitwiseAnd($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_BITWISE_AND, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_AND (type)'); + + }//end testBitwiseAnd() + + + /** + * Data provider. + * + * @see testBitwiseAnd() + * + * @return array> + */ + public static function dataBitwiseAnd() + { + return [ + 'in simple assignment 1' => ['/* testBitwiseAnd1 */'], + 'in simple assignment 2' => ['/* testBitwiseAnd2 */'], + 'in OO constant default value' => ['/* testBitwiseAndOOConstDefaultValue */'], + 'in property default value' => ['/* testBitwiseAndPropertyDefaultValue */'], + 'in method parameter default value' => ['/* testBitwiseAndParamDefaultValue */'], + 'reference for method parameter' => ['/* testBitwiseAnd3 */'], + 'in return statement' => ['/* testBitwiseAnd4 */'], + 'reference for function parameter' => ['/* testBitwiseAnd5 */'], + 'in OO constant default value DNF-like' => ['/* testBitwiseAndOOConstDefaultValueDNF */'], + 'in property default value DNF-like' => ['/* testBitwiseAndPropertyDefaultValueDNF */'], + 'in method parameter default value DNF-like' => ['/* testBitwiseAndParamDefaultValueDNF */'], + 'in closure parameter default value' => ['/* testBitwiseAndClosureParamDefault */'], + 'in arrow function parameter default value' => ['/* testBitwiseAndArrowParamDefault */'], + 'in arrow function return expression' => ['/* testBitwiseAndArrowExpression */'], + 'in long array key' => ['/* testBitwiseAndInArrayKey */'], + 'in long array value' => ['/* testBitwiseAndInArrayValue */'], + 'in short array key' => ['/* testBitwiseAndInShortArrayKey */'], + 'in short array value' => ['/* testBitwiseAndInShortArrayValue */'], + 'in parameter in function call' => ['/* testBitwiseAndNonArrowFnFunctionCall */'], + 'function return by reference' => ['/* testBitwiseAnd6 */'], + 'live coding / undetermined' => ['/* testLiveCoding */'], + ]; + + }//end dataBitwiseAnd() + + + /** + * Test that bitwise and tokens when used as part of a intersection type are tokenized as `T_TYPE_INTERSECTION`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataTypeIntersection + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTypeIntersection($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_TYPE_INTERSECTION, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_INTERSECTION (code)'); + $this->assertSame('T_TYPE_INTERSECTION', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_INTERSECTION (type)'); + + }//end testTypeIntersection() + + + /** + * Data provider. + * + * @see testTypeIntersection() + * + * @return array> + */ + public static function dataTypeIntersection() + { + return [ + 'type for OO constant' => ['/* testTypeIntersectionOOConstSimple */'], + 'type for OO constant, reversed modifier order' => ['/* testTypeIntersectionOOConstReverseModifierOrder */'], + 'type for OO constant, first of multi-intersect' => ['/* testTypeIntersectionOOConstMulti1 */'], + 'type for OO constant, middle of multi-intersect + comments' => ['/* testTypeIntersectionOOConstMulti2 */'], + 'type for OO constant, last of multi-intersect' => ['/* testTypeIntersectionOOConstMulti3 */'], + 'type for OO constant, using namespace relative names' => ['/* testTypeIntersectionOOConstNamespaceRelative */'], + 'type for OO constant, using partially qualified names' => ['/* testTypeIntersectionOOConstPartiallyQualified */'], + 'type for OO constant, using fully qualified names' => ['/* testTypeIntersectionOOConstFullyQualified */'], + 'type for static property' => ['/* testTypeIntersectionPropertySimple */'], + 'type for static property, reversed modifier order' => ['/* testTypeIntersectionPropertyReverseModifierOrder */'], + 'type for property, first of multi-intersect' => ['/* testTypeIntersectionPropertyMulti1 */'], + 'type for property, middle of multi-intersect, also comments' => ['/* testTypeIntersectionPropertyMulti2 */'], + 'type for property, last of multi-intersect' => ['/* testTypeIntersectionPropertyMulti3 */'], + 'type for property using namespace relative names' => ['/* testTypeIntersectionPropertyNamespaceRelative */'], + 'type for property using partially qualified names' => ['/* testTypeIntersectionPropertyPartiallyQualified */'], + 'type for property using fully qualified names' => ['/* testTypeIntersectionPropertyFullyQualified */'], + 'type for readonly property' => ['/* testTypeIntersectionPropertyWithReadOnlyKeyword */'], + 'type for static readonly property' => ['/* testTypeIntersectionPropertyWithStaticKeyword */'], + 'type for final property' => ['/* testTypeIntersectionWithPHP84FinalKeyword */'], + 'type for final property reversed modifier order' => ['/* testTypeIntersectionWithPHP84FinalKeywordFirst */'], + 'type for asymmetric visibility (private(set)) property' => ['/* testTypeIntersectionPropertyWithPrivateSet */'], + 'type for asymmetric visibility (public private(set)) prop' => ['/* testTypeIntersectionPropertyWithPublicPrivateSet */'], + 'type for asymmetric visibility (protected(set)) property' => ['/* testTypeIntersectionPropertyWithProtectedSet */'], + 'type for asymmetric visibility (public protected(set)) prop' => ['/* testTypeIntersectionPropertyWithPublicProtectedSet */'], + 'type for method parameter' => ['/* testTypeIntersectionParam1 */'], + 'type for method parameter, first in multi-intersect' => ['/* testTypeIntersectionParam2 */'], + 'type for method parameter, last in multi-intersect' => ['/* testTypeIntersectionParam3 */'], + 'type for method parameter with namespace relative names' => ['/* testTypeIntersectionParamNamespaceRelative */'], + 'type for method parameter with partially qualified names' => ['/* testTypeIntersectionParamPartiallyQualified */'], + 'type for method parameter with fully qualified names' => ['/* testTypeIntersectionParamFullyQualified */'], + 'type for property in constructor property promotion' => ['/* testTypeIntersectionConstructorPropertyPromotion */'], + 'return type for method' => ['/* testTypeIntersectionReturnType */'], + 'return type for method, first of multi-intersect' => ['/* testTypeIntersectionAbstractMethodReturnType1 */'], + 'return type for method, last of multi-intersect' => ['/* testTypeIntersectionAbstractMethodReturnType2 */'], + 'return type for method with namespace relative names' => ['/* testTypeIntersectionReturnTypeNamespaceRelative */'], + 'return type for method with partially qualified names' => ['/* testTypeIntersectionReturnPartiallyQualified */'], + 'return type for method with fully qualified names' => ['/* testTypeIntersectionReturnFullyQualified */'], + 'type for function parameter with reference' => ['/* testTypeIntersectionWithReference */'], + 'type for function parameter with spread operator' => ['/* testTypeIntersectionWithSpreadOperator */'], + 'DNF type for OO constant, union before DNF' => ['/* testTypeIntersectionConstantTypeUnionBeforeDNF */'], + 'DNF type for property, union after DNF' => ['/* testTypeIntersectionPropertyTypeUnionAfterDNF */'], + 'DNF type for function param, union before and after DNF' => ['/* testTypeIntersectionParamUnionBeforeAndAfterDNF */'], + 'DNF type for function return, union after DNF with null' => ['/* testTypeIntersectionReturnTypeUnionAfterDNF */'], + 'type for closure parameter with illegal nullable' => ['/* testTypeIntersectionClosureParamIllegalNullable */'], + 'return type for closure' => ['/* testTypeIntersectionClosureReturn */'], + 'type for arrow function parameter' => ['/* testTypeIntersectionArrowParam */'], + 'return type for arrow function' => ['/* testTypeIntersectionArrowReturnType */'], + 'type for function parameter, return by ref' => ['/* testTypeIntersectionNonArrowFunctionDeclaration */'], + 'type for function parameter with invalid types' => ['/* testTypeIntersectionWithInvalidTypes */'], + ]; + + }//end dataTypeIntersection() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.inc new file mode 100644 index 00000000..4c6212b7 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.inc @@ -0,0 +1,156 @@ +const ? 0 : 1; + +/* testGlobalConstantCannotBeTyped */ +const GLOBAL_UNTYPED = true; + +/* testGlobalConstantTypedShouldStillBeHandled */ +const ?int GLOBAL_TYPED = true; + +class ClassWithPlainTypedConstants { + /* testClassConstFinalUntyped */ + final const FINAL_UNTYPED = true; + + /* testClassConstVisibilityUntyped */ + public const /*comment*/VISIBLE_UNTYPED = true; + + /* testClassConstTypedTrue */ + const true TYPED_TRUE = true; + /* testClassConstTypedFalse */ + final const false TYPED_FALSE = false; + /* testClassConstTypedNull */ + public const null TYPED_NULL = null; + /* testClassConstTypedBool */ + final protected const/*comment*/bool TYPED_BOOL = false; + /* testClassConstTypedInt */ + private const int TYPED_INT = 0; + /* testClassConstTypedFloat */ + const float TYPED_FLOAT = 0.5; + /* testClassConstTypedString */ + public final const string/*comment*/TYPED_STRING = 'string'; + /* testClassConstTypedArray */ + private final const array TYPED_ARRAY = []; + /* testClassConstTypedObject */ + const + object + TYPED_OBJECT = MyClass::getInstance(); + /* testClassConstTypedIterable */ + const iterable typed_iterable = []; + /* testClassConstTypedMixed */ + const mixed TYPED_MIXED = 'string'; + + /* testClassConstTypedClassUnqualified */ + const MyClass TYPED_UNQUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedClassFullyQualified */ + public const \MyClass TYPED_FULLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedClassNamespaceRelative */ + protected const namespace\MyClass TYPED_NAMESPACE_RELATIVE_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedClassPartiallyQualified */ + private const Partial\MyClass TYPED_PARTIALLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedParent */ + const parent TYPED_PARENT = parent::getInstance(); + + // Illegal types - the fact that these are not allowed in PHP is not the concern of the PHPCS tokenizer. + /* testClassConstTypedCallable */ + protected const callable TYPED_CALLABLE = 'function_name'; + /* testClassConstTypedVoid */ + protected const void TYPED_VOID = null; + /* testClassConstTypedNever */ + protected const NEVER TYPED_NEVER = null; +} + +trait TraitWithNullableTypedConstants { + /* testTraitConstTypedNullableTrue */ + const ?true TYPED_TRUE = true; + /* testTraitConstTypedNullableFalse */ + final const ?false TYPED_FALSE = false; + /* testTraitConstTypedNullableNull */ + public const ?null TYPED_NULL = null; + /* testTraitConstTypedNullableBool */ + final protected const ?bool TYPED_BOOL = false; + /* testTraitConstTypedNullableInt */ + private const ?int TYPED_INT = 0; + /* testTraitConstTypedNullableFloat */ + const ? /*comment*/ float TYPED_FLOAT = 0.5; + /* testTraitConstTypedNullableString */ + public final const ?string TYPED_STRING = 'string'; + /* testTraitConstTypedNullableArray */ + private final const ? array TYPED_ARRAY = []; + /* testTraitConstTypedNullableObject */ + const ?object TYPED_OBJECT = MyClass::getInstance(); + /* testTraitConstTypedNullableIterable */ + const ?iterable TYPED_ITERABLE = []; + /* testTraitConstTypedNullableMixed */ + const ?mixed TYPED_MIXED = 'string'; + + /* testTraitConstTypedNullableClassUnqualified */ + const ?MyClass TYPED_UNQUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableClassFullyQualified */ + public const ?\MyClass TYPED_FULLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableClassNamespaceRelative */ + protected const ?namespace\MyClass TYPED_NAMESPACE_RELATIVE_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableClassPartiallyQualified */ + private const ?Partial\MyClass TYPED_PARTIALLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableParent */ + const ?parent TYPED_PARENT = parent::getInstance(); +} + +interface InterfaceWithUnionTypedConstants { + /* testInterfaceConstTypedUnionTrueNull */ + const true|null /*comment*/ UNION_TRUE_NULL = true; + /* testInterfaceConstTypedUnionArrayObject */ + const array|object UNION_ARRAY_OBJECT = []; + /* testInterfaceConstTypedUnionStringArrayInt */ + const string | array | int UNION_STRING_ARRAY_INT = 'array middle'; + /* testInterfaceConstTypedUnionFloatBoolArray */ + const float /*comment*/| bool|array UNION_FLOAT_BOOL_ARRAY = false; + /* testInterfaceConstTypedUnionIterableFalse */ + const iterable|false UNION_ITERABLE_FALSE = false; + /* testInterfaceConstTypedUnionUnqualifiedNamespaceRelative */ + const Unqualified|namespace\Relative UNION_UNQUALIFIED_NSRELATIVE = new Unqualified(); + /* testInterfaceConstTypedUnionFullyQualifiedPartiallyQualified */ + const \Fully\Qualified|Partially\Qualified UNION_FQN_PARTIAL = new Partial\Qualified; +} + +enum EnumWithIntersectionTypedConstants { + // Illegal types in a class, but legal in an enum. + /* testEnumConstTypedSelf */ + final const self TYPED_SELF = self::getInstance(); + /* testEnumConstTypedStatic */ + const static TYPED_STATIC = static::getInstance(); + /* testEnumConstTypedNullableSelf */ + public const ?self TYPED_SELF = self::getInstance(); + /* testEnumConstTypedNullableStatic */ + const ?static TYPED_STATIC = static::getInstance(); + + /* testEnumConstTypedIntersectUnqualifiedNamespaceRelative */ + const Unqualified&namespace\Relative UNION_UNQUALIFIED_NSRELATIVE = new Unqualified(); + /* testEnumConstTypedIntersectFullyQualifiedPartiallyQualified */ + const \Fully\Qualified&Partially\Qualified UNION_FQN_PARTIAL = new Partial\Qualified; +} + +$anonClassWithDNFTypes = new class() extends Something { + /* testAnonClassConstDNFTypeNullAfter */ + const (A&B)|null DNF_OR_NULL_1 = null; + /* testAnonClassConstDNFTypeNullBefore */ + public final const NULL|(A&B) DNF_OR_NULL_2 = null; + /* testAnonClassConstDNFTypeFalseBefore */ + final const false|(C&D) DNF_OR_FALSE = false; + /* testAnonClassConstDNFTypeTrueAfter */ + private final const ( F & G ) | true DNF_OR_ARRAY = true; + /* testAnonClassConstDNFTypeTrueBeforeFalseAfter */ + public const TRUE|(SplBool&Stringable)|FALSE DNF_OR_BOOL = true; + /* testAnonClassConstDNFTypeArrayAfter */ + final protected const (Traversable&Countable)|array DNF_OR_ARRAY_1 = []; + /* testAnonClassConstDNFTypeArrayBefore */ + private const array /*comment*/ | ( Traversable /*comment*/ & Countable ) DNF_OR_ARRAY_2 = new MyClass; + /* testAnonClassConstDNFTypeInvalidNullable */ + const ? (Invalid&Fatal)|NullableNotAllowed DNF = null; + + /* testAnonClassConstDNFTypeFQNRelativePartiallyQualified */ + const (\FQN&namespace\Relative)|Partially\Qualified DNF_CLASSNAME = MyClass::getInstance(); + /* testAnonClassConstDNFTypeParentSelfStatic */ + const (parent&self)|static DNF_PARENT = parent::getInstance(); +}; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.php new file mode 100644 index 00000000..6968c4ef --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.php @@ -0,0 +1,668 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class TypedConstantsTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that a ? after a "const" which is not the constant keyword is tokenized as ternary then, not as the nullable operator. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTernaryIsInlineThen() + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken('/* testTernaryIsTernaryAfterConst */', [T_NULLABLE, T_INLINE_THEN]); + + $this->assertSame( + T_INLINE_THEN, + $tokens[$target]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$target]['code']).', not T_INLINE_THEN (code)' + ); + $this->assertSame( + 'T_INLINE_THEN', + $tokens[$target]['type'], + 'Token tokenized as '.$tokens[$target]['type'].', not T_INLINE_THEN (type)' + ); + + }//end testTernaryIsInlineThen() + + + /** + * Test the token name for an untyped constant is tokenized as T_STRING. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataUntypedConstant + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testUntypedConstant($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, T_CONST); + + for ($i = ($target + 1); $tokens[$i]['code'] !== T_EQUAL; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + // Ignore whitespace and comments, not interested in the tokenization of those. + continue; + } + + $this->assertSame( + T_STRING, + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not T_STRING (code)' + ); + $this->assertSame( + 'T_STRING', + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not T_STRING (type)' + ); + } + + }//end testUntypedConstant() + + + /** + * Data provider. + * + * @see testUntypedConstant() + * + * @return array> + */ + public static function dataUntypedConstant() + { + return [ + 'non OO constant (untyped)' => [ + 'testMarker' => '/* testGlobalConstantCannotBeTyped */', + ], + 'OO constant, final, untyped' => [ + 'testMarker' => '/* testClassConstFinalUntyped */', + ], + 'OO constant, public, untyped, with comment' => [ + 'testMarker' => '/* testClassConstVisibilityUntyped */', + ], + ]; + + }//end dataUntypedConstant() + + + /** + * Test the tokens in the type of a typed constant as well as the constant name are tokenized correctly. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $sequence The expected token sequence. + * + * @dataProvider dataTypedConstant + * @dataProvider dataNullableTypedConstant + * @dataProvider dataUnionTypedConstant + * @dataProvider dataIntersectionTypedConstant + * @dataProvider dataDNFTypedConstant + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTypedConstant($testMarker, array $sequence) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, T_CONST); + + $current = 0; + for ($i = ($target + 1); $tokens[$i]['code'] !== T_EQUAL; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + // Ignore whitespace and comments, not interested in the tokenization of those. + continue; + } + + $this->assertSame( + $sequence[$current], + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.Tokens::tokenName($sequence[$current]).' (code)' + ); + + ++$current; + } + + }//end testTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataTypedConstant() + { + $data = [ + 'simple type: true' => [ + 'testMarker' => '/* testClassConstTypedTrue */', + 'sequence' => [T_TRUE], + ], + 'simple type: false' => [ + 'testMarker' => '/* testClassConstTypedFalse */', + 'sequence' => [T_FALSE], + ], + 'simple type: null' => [ + 'testMarker' => '/* testClassConstTypedNull */', + 'sequence' => [T_NULL], + ], + 'simple type: bool' => [ + 'testMarker' => '/* testClassConstTypedBool */', + 'sequence' => [T_STRING], + ], + 'simple type: int' => [ + 'testMarker' => '/* testClassConstTypedInt */', + 'sequence' => [T_STRING], + ], + 'simple type: float' => [ + 'testMarker' => '/* testClassConstTypedFloat */', + 'sequence' => [T_STRING], + ], + 'simple type: string' => [ + 'testMarker' => '/* testClassConstTypedString */', + 'sequence' => [T_STRING], + ], + 'simple type: array' => [ + 'testMarker' => '/* testClassConstTypedArray */', + 'sequence' => [T_STRING], + ], + 'simple type: object' => [ + 'testMarker' => '/* testClassConstTypedObject */', + 'sequence' => [T_STRING], + ], + 'simple type: iterable' => [ + 'testMarker' => '/* testClassConstTypedIterable */', + 'sequence' => [T_STRING], + ], + 'simple type: mixed' => [ + 'testMarker' => '/* testClassConstTypedMixed */', + 'sequence' => [T_STRING], + ], + 'simple type: unqualified name' => [ + 'testMarker' => '/* testClassConstTypedClassUnqualified */', + 'sequence' => [T_STRING], + ], + 'simple type: fully qualified name' => [ + 'testMarker' => '/* testClassConstTypedClassFullyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'simple type: namespace relative name' => [ + 'testMarker' => '/* testClassConstTypedClassNamespaceRelative */', + 'sequence' => [ + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'simple type: partially qualified name' => [ + 'testMarker' => '/* testClassConstTypedClassPartiallyQualified */', + 'sequence' => [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'simple type: parent' => [ + 'testMarker' => '/* testClassConstTypedParent */', + 'sequence' => [T_PARENT], + ], + + 'simple type: callable (invalid)' => [ + 'testMarker' => '/* testClassConstTypedCallable */', + 'sequence' => [T_CALLABLE], + ], + 'simple type: void (invalid)' => [ + 'testMarker' => '/* testClassConstTypedVoid */', + 'sequence' => [T_STRING], + ], + 'simple type: NEVER (invalid)' => [ + 'testMarker' => '/* testClassConstTypedNever */', + 'sequence' => [T_STRING], + ], + + 'simple type: self (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedSelf */', + 'sequence' => [T_SELF], + ], + 'simple type: static (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedStatic */', + 'sequence' => [T_STATIC], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataNullableTypedConstant() + { + $data = [ + // Global constants cannot be typed in PHP, but that's not our concern. + 'global typed constant, invalid, ?int' => [ + 'testMarker' => '/* testGlobalConstantTypedShouldStillBeHandled */', + 'sequence' => [T_STRING], + ], + + // OO constants. + 'nullable type: true' => [ + 'testMarker' => '/* testTraitConstTypedNullableTrue */', + 'sequence' => [T_TRUE], + ], + 'nullable type: false' => [ + 'testMarker' => '/* testTraitConstTypedNullableFalse */', + 'sequence' => [T_FALSE], + ], + 'nullable type: null' => [ + 'testMarker' => '/* testTraitConstTypedNullableNull */', + 'sequence' => [T_NULL], + ], + 'nullable type: bool' => [ + 'testMarker' => '/* testTraitConstTypedNullableBool */', + 'sequence' => [T_STRING], + ], + 'nullable type: int' => [ + 'testMarker' => '/* testTraitConstTypedNullableInt */', + 'sequence' => [T_STRING], + ], + 'nullable type: float' => [ + 'testMarker' => '/* testTraitConstTypedNullableFloat */', + 'sequence' => [T_STRING], + ], + 'nullable type: string' => [ + 'testMarker' => '/* testTraitConstTypedNullableString */', + 'sequence' => [T_STRING], + ], + 'nullable type: array' => [ + 'testMarker' => '/* testTraitConstTypedNullableArray */', + 'sequence' => [T_STRING], + ], + 'nullable type: object' => [ + 'testMarker' => '/* testTraitConstTypedNullableObject */', + 'sequence' => [T_STRING], + ], + 'nullable type: iterable' => [ + 'testMarker' => '/* testTraitConstTypedNullableIterable */', + 'sequence' => [T_STRING], + ], + 'nullable type: mixed' => [ + 'testMarker' => '/* testTraitConstTypedNullableMixed */', + 'sequence' => [T_STRING], + ], + 'nullable type: unqualified name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassUnqualified */', + 'sequence' => [T_STRING], + ], + 'nullable type: fully qualified name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassFullyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'nullable type: namespace relative name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassNamespaceRelative */', + 'sequence' => [ + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'nullable type: partially qualified name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassPartiallyQualified */', + 'sequence' => [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'nullable type: parent' => [ + 'testMarker' => '/* testTraitConstTypedNullableParent */', + 'sequence' => [T_PARENT], + ], + + 'nullable type: self (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedNullableSelf */', + 'sequence' => [T_SELF], + ], + 'nullable type: static (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedNullableStatic */', + 'sequence' => [T_STATIC], + ], + ]; + + // The nullable operator, as the first token in the sequence, is always T_NULLABLE. + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + array_unshift($data[$key]['sequence'], T_NULLABLE); + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataNullableTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataUnionTypedConstant() + { + $data = [ + 'union type: true|null' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionTrueNull */', + 'sequence' => [ + T_TRUE, + T_TYPE_UNION, + T_NULL, + ], + ], + 'union type: array|object' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionArrayObject */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_STRING, + ], + ], + 'union type: string|array|int' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionStringArrayInt */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_STRING, + T_TYPE_UNION, + T_STRING, + ], + ], + 'union type: float|bool|array' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionFloatBoolArray */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_STRING, + T_TYPE_UNION, + T_STRING, + ], + ], + 'union type: iterable|false' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionIterableFalse */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_FALSE, + ], + ], + 'union type: Unqualified|Namespace\Relative' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionUnqualifiedNamespaceRelative */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'union type: FQN|Partial' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionFullyQualifiedPartiallyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_UNION, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataUnionTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataIntersectionTypedConstant() + { + $data = [ + 'intersection type: Unqualified&Namespace\Relative' => [ + 'testMarker' => '/* testEnumConstTypedIntersectUnqualifiedNamespaceRelative */', + 'sequence' => [ + T_STRING, + T_TYPE_INTERSECTION, + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'intersection type: FQN&Partial' => [ + 'testMarker' => '/* testEnumConstTypedIntersectFullyQualifiedPartiallyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataIntersectionTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataDNFTypedConstant() + { + $data = [ + 'DNF type: null after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeNullAfter */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_NULL, + ], + ], + 'DNF type: null before' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeNullBefore */', + 'sequence' => [ + T_NULL, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + ], + ], + 'DNF type: false before' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeFalseBefore */', + 'sequence' => [ + T_FALSE, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + ], + ], + 'DNF type: true after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeTrueAfter */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_TRUE, + ], + ], + 'DNF type: true before, false after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeTrueBeforeFalseAfter */', + 'sequence' => [ + T_TRUE, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_FALSE, + ], + ], + 'DNF type: array after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeArrayAfter */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STRING, + ], + ], + 'DNF type: array before' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeArrayBefore */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + ], + ], + 'DNF type: invalid nullable DNF' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeInvalidNullable */', + 'sequence' => [ + T_NULLABLE, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STRING, + ], + ], + 'DNF type: FQN/namespace relative/partially qualified names' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeFQNRelativePartiallyQualified */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_INTERSECTION, + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'DNF type: invalid self/parent/static' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeParentSelfStatic */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_PARENT, + T_TYPE_INTERSECTION, + T_SELF, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STATIC, + ], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataDNFTypedConstant() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.inc new file mode 100644 index 00000000..65c551a8 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.inc @@ -0,0 +1,147 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class UndoNamespacedNameSingleTokenTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that identifier names are tokenized the same across PHP versions, based on the PHP 5/7 tokenization. + * + * @param string $testMarker The comment prefacing the test. + * @param array> $expectedTokens The tokenization expected. + * + * @dataProvider dataIdentifierTokenization + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testIdentifierTokenization($testMarker, $expectedTokens) + { + $tokens = $this->phpcsFile->getTokens(); + $identifier = $this->getTargetToken($testMarker, constant($expectedTokens[0]['type'])); + + foreach ($expectedTokens as $tokenInfo) { + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$identifier]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$identifier]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$identifier]['type'], + 'Token tokenized as '.$tokens[$identifier]['type'].', not '.$tokenInfo['type'].' (type)' + ); + $this->assertSame($tokenInfo['content'], $tokens[$identifier]['content']); + + ++$identifier; + } + + }//end testIdentifierTokenization() + + + /** + * Data provider. + * + * @see testIdentifierTokenization() + * + * @return array>>> + */ + public static function dataIdentifierTokenization() + { + return [ + 'namespace declaration' => [ + 'testMarker' => '/* testNamespaceDeclaration */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Package', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'namespace declaration, multi-level' => [ + 'testMarker' => '/* testNamespaceDeclarationWithLevels */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Vendor', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'SubLevel', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Domain', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'import use statement, class' => [ + 'testMarker' => '/* testUseStatement */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'import use statement, class, multi-level' => [ + 'testMarker' => '/* testUseStatementWithLevels */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Vendor', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Domain', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'import use statement, function' => [ + 'testMarker' => '/* testFunctionUseStatement */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'function', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function_name', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'import use statement, function, multi-level' => [ + 'testMarker' => '/* testFunctionUseStatementWithLevels */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'function', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Vendor', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function_in_ns', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'import use statement, constant' => [ + 'testMarker' => '/* testConstantUseStatement */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'const', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'CONSTANT_NAME', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'import use statement, constant, multi-level' => [ + 'testMarker' => '/* testConstantUseStatementWithLevels */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'const', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Vendor', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'OTHER_CONSTANT', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'import use statement, multi-statement, unqualified class' => [ + 'testMarker' => '/* testMultiUseUnqualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'UnqualifiedClassName', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + ], + ], + 'import use statement, multi-statement, partially qualified class' => [ + 'testMarker' => '/* testMultiUsePartiallyQualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Sublevel', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'PartiallyClassName', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'group use statement, multi-level prefix, mix inside group' => [ + 'testMarker' => '/* testGroupUseStatement */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Vendor', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_OPEN_USE_GROUP', + 'content' => '{', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'AnotherDomain', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function_grouped', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'const', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'CONSTANT_GROUPED', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Sub', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'YetAnotherDomain', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'SubLevelA', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function_grouped_too', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'const', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'SubLevelB', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'CONSTANT_GROUPED_TOO', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_CLOSE_USE_GROUP', + 'content' => '}', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'class declaration' => [ + 'testMarker' => '/* testClassName */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'MyClass', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'class declaration, extends fully qualified name' => [ + 'testMarker' => '/* testExtendedFQN */', + 'expectedTokens' => [ + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Vendor', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'FQN', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'class declaration, implements namespace relative name' => [ + 'testMarker' => '/* testImplementsRelative */', + 'expectedTokens' => [ + [ + 'type' => 'T_NAMESPACE', + 'content' => 'namespace', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Name', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + ], + ], + 'class declaration, implements fully qualified name' => [ + 'testMarker' => '/* testImplementsFQN */', + 'expectedTokens' => [ + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Fully', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Qualified', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + ], + ], + 'class declaration, implements unqualified name' => [ + 'testMarker' => '/* testImplementsUnqualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Unqualified', + ], + [ + 'type' => 'T_COMMA', + 'content' => ',', + ], + ], + ], + 'class declaration, implements partially qualified name' => [ + 'testMarker' => '/* testImplementsPartiallyQualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Sub', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Name', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'method declaration' => [ + 'testMarker' => '/* testFunctionName */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'function_name', + ], + [ + 'type' => 'T_OPEN_PARENTHESIS', + 'content' => '(', + ], + ], + ], + 'param type declaration, namespace relative name' => [ + 'testMarker' => '/* testTypeDeclarationRelative */', + 'expectedTokens' => [ + [ + 'type' => 'T_NAMESPACE', + 'content' => 'namespace', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Name', + ], + [ + 'type' => 'T_TYPE_UNION', + 'content' => '|', + ], + [ + 'type' => 'T_STRING', + 'content' => 'object', + ], + ], + ], + 'param type declaration, fully qualified name' => [ + 'testMarker' => '/* testTypeDeclarationFQN */', + 'expectedTokens' => [ + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Fully', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Qualified', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Name', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'param type declaration, unqualified name' => [ + 'testMarker' => '/* testTypeDeclarationUnqualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Unqualified', + ], + [ + 'type' => 'T_TYPE_UNION', + 'content' => '|', + ], + [ + 'type' => 'T_FALSE', + 'content' => 'false', + ], + ], + ], + 'param type declaration, partially qualified name' => [ + 'testMarker' => '/* testTypeDeclarationPartiallyQualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_NULLABLE', + 'content' => '?', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Sublevel', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Name', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'return type declaration, fully qualified name' => [ + 'testMarker' => '/* testReturnTypeFQN */', + 'expectedTokens' => [ + [ + 'type' => 'T_NULLABLE', + 'content' => '?', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Name', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'function call, namespace relative name' => [ + 'testMarker' => '/* testFunctionCallRelative */', + 'expectedTokens' => [ + [ + 'type' => 'T_NAMESPACE', + 'content' => 'NameSpace', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function_name', + ], + [ + 'type' => 'T_OPEN_PARENTHESIS', + 'content' => '(', + ], + ], + ], + 'function call, fully qualified name' => [ + 'testMarker' => '/* testFunctionCallFQN */', + 'expectedTokens' => [ + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Vendor', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Package', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function_name', + ], + [ + 'type' => 'T_OPEN_PARENTHESIS', + 'content' => '(', + ], + ], + ], + 'function call, unqualified name' => [ + 'testMarker' => '/* testFunctionCallUnqualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'function_name', + ], + [ + 'type' => 'T_OPEN_PARENTHESIS', + 'content' => '(', + ], + ], + ], + 'function call, partially qualified name' => [ + 'testMarker' => '/* testFunctionCallPartiallyQualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function_name', + ], + [ + 'type' => 'T_OPEN_PARENTHESIS', + 'content' => '(', + ], + ], + ], + 'catch, namespace relative name' => [ + 'testMarker' => '/* testCatchRelative */', + 'expectedTokens' => [ + [ + 'type' => 'T_NAMESPACE', + 'content' => 'namespace', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'SubLevel', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Exception', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'catch, fully qualified name' => [ + 'testMarker' => '/* testCatchFQN */', + 'expectedTokens' => [ + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Exception', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'catch, unqualified name' => [ + 'testMarker' => '/* testCatchUnqualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Exception', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'catch, partially qualified name' => [ + 'testMarker' => '/* testCatchPartiallyQualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Exception', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'class instantiation, namespace relative name' => [ + 'testMarker' => '/* testNewRelative */', + 'expectedTokens' => [ + [ + 'type' => 'T_NAMESPACE', + 'content' => 'namespace', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_OPEN_PARENTHESIS', + 'content' => '(', + ], + ], + ], + 'class instantiation, fully qualified name' => [ + 'testMarker' => '/* testNewFQN */', + 'expectedTokens' => [ + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Vendor', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_OPEN_PARENTHESIS', + 'content' => '(', + ], + ], + ], + 'class instantiation, unqualified name' => [ + 'testMarker' => '/* testNewUnqualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'class instantiation, partially qualified name' => [ + 'testMarker' => '/* testNewPartiallyQualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'double colon class access, namespace relative name' => [ + 'testMarker' => '/* testDoubleColonRelative */', + 'expectedTokens' => [ + [ + 'type' => 'T_NAMESPACE', + 'content' => 'namespace', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_DOUBLE_COLON', + 'content' => '::', + ], + ], + ], + 'double colon class access, fully qualified name' => [ + 'testMarker' => '/* testDoubleColonFQN */', + 'expectedTokens' => [ + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_DOUBLE_COLON', + 'content' => '::', + ], + ], + ], + 'double colon class access, unqualified name' => [ + 'testMarker' => '/* testDoubleColonUnqualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_DOUBLE_COLON', + 'content' => '::', + ], + ], + ], + 'double colon class access, partially qualified name' => [ + 'testMarker' => '/* testDoubleColonPartiallyQualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Level', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_DOUBLE_COLON', + 'content' => '::', + ], + ], + ], + 'instanceof, namespace relative name' => [ + 'testMarker' => '/* testInstanceOfRelative */', + 'expectedTokens' => [ + [ + 'type' => 'T_NAMESPACE', + 'content' => 'namespace', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'instanceof, fully qualified name' => [ + 'testMarker' => '/* testInstanceOfFQN */', + 'expectedTokens' => [ + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Full', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_CLOSE_PARENTHESIS', + 'content' => ')', + ], + ], + ], + 'instanceof, unqualified name' => [ + 'testMarker' => '/* testInstanceOfUnqualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'instanceof, partially qualified name' => [ + 'testMarker' => '/* testInstanceOfPartiallyQualified */', + 'expectedTokens' => [ + [ + 'type' => 'T_STRING', + 'content' => 'Partially', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'ClassName', + ], + [ + 'type' => 'T_SEMICOLON', + 'content' => ';', + ], + ], + ], + 'function call, namespace relative, with whitespace (invalid in PHP 8)' => [ + 'testMarker' => '/* testInvalidInPHP8Whitespace */', + 'expectedTokens' => [ + [ + 'type' => 'T_NAMESPACE', + 'content' => 'namespace', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Sublevel', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_STRING', + 'content' => 'function_name', + ], + [ + 'type' => 'T_OPEN_PARENTHESIS', + 'content' => '(', + ], + ], + ], + 'double colon class access, fully qualified, with whitespace and comments (invalid in PHP 8)' => [ + 'testMarker' => '/* testInvalidInPHP8Comments */', + 'expectedTokens' => [ + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Fully', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat.Sniff -- for reasons +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Qualified', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '/* comment */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_NS_SEPARATOR', + 'content' => '\\', + ], + [ + 'type' => 'T_STRING', + 'content' => 'Name', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + ]; + + }//end dataIdentifierTokenization() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.inc new file mode 100644 index 00000000..3130b846 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.inc @@ -0,0 +1,77 @@ +yield; + + /* testYieldUsedAsPropertyName2 */ + echo $obj?->yield(); + + /* testYieldUsedForClassConstantAccess1 */ + echo MyClass::YIELD; + /* testFromUsedForClassConstantAccess1 */ + echo MyClass::FROM; + } + + /* testYieldUsedAsMethodNameReturnByRef */ + public function &yield() {} +} + +function myGen() { + /* testYieldLiveCoding */ + yield diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.php new file mode 100644 index 00000000..efb12096 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.php @@ -0,0 +1,448 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests the tokenization of the `yield` and `yield from` keywords. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class YieldTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the yield keyword is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent Expected token content. + * + * @dataProvider dataYieldKeyword + * + * @return void + */ + public function testYieldKeyword($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_YIELD, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD (code)'); + + // This assertion would fail on PHP 5.4 with PHPUnit 4 as PHPUnit polyfills the `T_YIELD` token too, but + // with a different value, which causes the token 'type' to be set to `UNKNOWN`. + // This issue _only_ occurs when running the tests, not when running PHPCS outside of a test situation. + // The PHPUnit polyfilled token is declared in the PHP_CodeCoverage_Report_HTML_Renderer_File class + // in vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/File.php. + if (PHP_VERSION_ID >= 50500) { + $this->assertSame('T_YIELD', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD (type)'); + } + + $this->assertSame($expectedContent, $tokenArray['content'], 'Token content does not match expectation'); + + }//end testYieldKeyword() + + + /** + * Data provider. + * + * @see testYieldKeyword() + * + * @return array> + */ + public static function dataYieldKeyword() + { + return [ + 'yield' => [ + 'testMarker' => '/* testYield */', + 'expectedContent' => 'yield', + ], + 'yield followed by comment' => [ + 'testMarker' => '/* testYieldFollowedByComment */', + 'expectedContent' => 'YIELD', + ], + 'yield at end of file, live coding' => [ + 'testMarker' => '/* testYieldLiveCoding */', + 'expectedContent' => 'yield', + ], + ]; + + }//end dataYieldKeyword() + + + /** + * Test that the yield from keyword is tokenized as a single token when it in on a single line + * and only has whitespace between the words. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent Expected token content. + * + * @dataProvider dataYieldFromKeywordSingleToken + * + * @return void + */ + public function testYieldFromKeywordSingleToken($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_YIELD_FROM, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD_FROM (code)'); + $this->assertSame('T_YIELD_FROM', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD_FROM (type)'); + + if (isset($tokenArray['orig_content']) === true) { + $this->assertSame($expectedContent, $tokenArray['orig_content'], 'Token (orig) content does not match expectation'); + } else { + $this->assertSame($expectedContent, $tokenArray['content'], 'Token content does not match expectation'); + } + + }//end testYieldFromKeywordSingleToken() + + + /** + * Data provider. + * + * @see testYieldFromKeywordSingleToken() + * + * @return array> + */ + public static function dataYieldFromKeywordSingleToken() + { + return [ + 'yield from' => [ + 'testMarker' => '/* testYieldFrom */', + 'expectedContent' => 'yield from', + ], + 'yield from with extra space between' => [ + 'testMarker' => '/* testYieldFromWithExtraSpacesBetween */', + 'expectedContent' => 'Yield From', + ], + 'yield from with tab between' => [ + 'testMarker' => '/* testYieldFromWithTabBetween */', + 'expectedContent' => 'yield from', + ], + ]; + + }//end dataYieldFromKeywordSingleToken() + + + /** + * Test that the yield from keyword is tokenized as a single token when it in on a single line + * and only has whitespace between the words. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array> $expectedTokens The tokenization expected. + * + * @dataProvider dataYieldFromKeywordMultiToken + * + * @return void + */ + public function testYieldFromKeywordMultiToken($testMarker, $expectedTokens) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + + foreach ($expectedTokens as $nr => $tokenInfo) { + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$target]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$target]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$target]['type'], + 'Token tokenized as '.$tokens[$target]['type'].', not '.$tokenInfo['type'].' (type)' + ); + $this->assertSame( + $tokenInfo['content'], + $tokens[$target]['content'], + 'Content of token '.($nr + 1).' ('.$tokens[$target]['type'].') does not match expectations' + ); + + ++$target; + } + + }//end testYieldFromKeywordMultiToken() + + + /** + * Data provider. + * + * @see testYieldFromKeywordMultiToken() + * + * @return array>>> + */ + public static function dataYieldFromKeywordMultiToken() + { + return [ + 'yield from with new line' => [ + 'testMarker' => '/* testYieldFromSplitByNewLines */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'FROM', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'yield from with comment' => [ + 'testMarker' => '/* testYieldFromSplitByComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '/* comment */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'yield from with trailing comment' => [ + 'testMarker' => '/* testYieldFromWithTrailingComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'yield from with trailing annotation' => [ + 'testMarker' => '/* testYieldFromWithTrailingAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat.Sniff -- for reasons. +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'yield from with new line and comment' => [ + 'testMarker' => '/* testYieldFromSplitByNewLineAndComments */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '/* comment line 1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' line 2 */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// another comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'yield from with new line and annotation' => [ + 'testMarker' => '/* testYieldFromSplitByNewLineAndAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'YIELD', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_DISABLE', + 'content' => '// @phpcs:disable Stnd.Cat.Sniff -- for reasons. +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'From', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + ]; + + }//end dataYieldFromKeywordMultiToken() + + + /** + * Test that 'yield' or 'from' when not used as the reserved keyword are tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataYieldNonKeyword + * + * @return void + */ + public function testYieldNonKeyword($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testYieldNonKeyword() + + + /** + * Data provider. + * + * @see testYieldNonKeyword() + * + * @return array> + */ + public static function dataYieldNonKeyword() + { + return [ + 'yield used as class name' => ['/* testYieldUsedAsClassName */'], + 'yield used as class constant name' => ['/* testYieldUsedAsClassConstantName */'], + 'yield used as method name' => ['/* testYieldUsedAsMethodName */'], + 'yield used as property access 1' => ['/* testYieldUsedAsPropertyName1 */'], + 'yield used as property access 2' => ['/* testYieldUsedAsPropertyName2 */'], + 'yield used as class constant access' => ['/* testYieldUsedForClassConstantAccess1 */'], + 'from used as class constant access' => ['/* testFromUsedForClassConstantAccess1 */'], + 'yield used as method name with ref' => ['/* testYieldUsedAsMethodNameReturnByRef */'], + ]; + + }//end dataYieldNonKeyword() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.inc new file mode 100644 index 00000000..89031bd1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.inc @@ -0,0 +1,185 @@ + 10 ) {} + +/* testParensOwnerFor */ +for ($i =0; $i < /* testParensNoOwnerInForCondition */ ( CONST_A & CONST_B ); $i++ ); + +/* testParensOwnerMatch */ +$match = match(CONST_A & CONST_B) { + default => $a, +}; + +/* testParensOwnerArray */ +$array = array ( + 'text', + \CONST_A & \Fully\Qualified\CONST_B, + /* testParensNoOwnerFunctionCallWithAmpersandInCallable */ + do_something($a, /* testParensOwnerArrowFn */ fn($b) => $a & $b, $c), +); + +/* testParensOwnerListWithRefVars */ +list(&$a, &$b) = $array; + +/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */ +$obj->static((CONST_A&CONST_B)|CONST_C | $var); + + +/* + * DNF parentheses. + */ + +abstract class DNFTypes { + /* testDNFTypeOOConstUnqualifiedClasses */ + public const (A&B)|D UNQUALIFIED = new Foo; + + /* testDNFTypeOOConstReverseModifierOrder */ + protected final const int|(Foo&Bar)|float MODIFIERS_REVERSED /* testParensNoOwnerOOConstDefaultValue */ = (E_WARNING & E_NOTICE) | E_DEPRECATED; + + const + /* testDNFTypeOOConstMulti1 */ + (A&B) | + /* testDNFTypeOOConstMulti2 */ + (C&D) | // phpcs:ignore Stnd.Cat.Sniff + /* testDNFTypeOOConstMulti3 */ + (Y&D) + | null MULTI_DNF = null; + + /* testDNFTypeOOConstNamespaceRelative */ + final protected const (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC NAMESPACE_RELATIVE = new namespace\Sub\NameB; + + /* testDNFTypeOOConstPartiallyQualified */ + const Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) PARTIALLY_QUALIFIED = new Partially\Qualified\NameA; + + /* testDNFTypeOOConstFullyQualified */ + const (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameC FULLY_QUALIFIED = new \Fully\Qualified\NameB(); + + /* testDNFTypePropertyUnqualifiedClasses */ + public static (Foo&Bar)|array $obj; + + /* testDNFTypePropertyReverseModifierOrder */ + static protected string|(A&B)|int $dnf /* testParensNoOwnerPropertyDefaultValue1 */ = ( E_WARNING & E_NOTICE ) | /* testParensNoOwnerPropertyDefaultValue2 */ (E_ALL & E_DEPRECATED); + + private + /* testDNFTypePropertyMultiNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB) | + /* testDNFTypePropertyMultiPartiallyQualified */ + (Partially\Qualified\NameA&Partially\Qualified\NameB) | // phpcs:ignore Stnd.Cat.Sniff + false + /* testDNFTypePropertyMultiFullyQualified */ + | (\Fully\Qualified\NameA&\Fully\Qualified\NameB) $multiDnf; + + /* testDNFTypePropertyWithReadOnlyKeyword1 */ + protected readonly (A&B) | /* testDNFTypePropertyWithReadOnlyKeyword2 */ (C&D) $readonly; + + /* testDNFTypePropertyWithStaticAndReadOnlyKeywords */ + static readonly (A&B&C)|array $staticReadonly; + + /* testDNFTypePropertyWithOnlyStaticKeyword */ + static (A&B&C)|true $onlyStaticModified; + + public function paramTypes( + /* testDNFTypeParam1WithAttribute */ + #[MyAttribute] + (\Foo&Bar)|int|float $paramA /* testParensNoOwnerParamDefaultValue */ = SOMETHING | (CONSTANT_A & CONSTANT_B), + + /* testDNFTypeParam2 */ + (Foo&\Bar) /* testDNFTypeParam3 */ |(Baz&Fop) &...$paramB, + ) { + /* testParensNoOwnerInReturnValue1 */ + return ( + /* testParensNoOwnerInReturnValue2 */ + ($a1 & $b1) | + /* testParensNoOwnerInReturnValue3 */ + ($a2 & $b2) + ) + $c; + } + + public function identifierNames( + /* testDNFTypeParamNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB)|false $paramA, + /* testDNFTypeParamPartiallyQualified */ + Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) $paramB, + /* testDNFTypeParamFullyQualified */ + name|(\Fully\Qualified\NameA&\Fully\Qualified\NameB) $paramC, + ) {} + + public function __construct( + /* testDNFTypeConstructorPropertyPromotion1 */ + public (A&B)| /* testDNFTypeConstructorPropertyPromotion2 */ (A&D) $property + ) {} + + public function returnType()/* testDNFTypeReturnType1 */ : A|(B&D)|/* testDNFTypeReturnType2 */(B&W)|null {} + + abstract public function abstractMethod(): /* testDNFTypeAbstractMethodReturnType1 */ (X&Y) /* testDNFTypeAbstractMethodReturnType2 */ |(W&Z); + + public function identifierNamesReturnRelative( + ) : /* testDNFTypeReturnTypeNamespaceRelative */ (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC {} + + public function identifierNamesReturnPQ( + ) : /* testDNFTypeReturnPartiallyQualified */Partially\Qualified\NameA|(Partially\Qualified\NameB&Partially\Qualified\NameC) {} + + // Illegal type: segments which are strict subsets of others are disallowed, but that's not the concern of the tokenizer. + public function identifierNamesReturnFQ( + ) /* testDNFTypeReturnFullyQualified */ : (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameB {} +} + +function globalFunctionWithSpreadAndReference( + /* testDNFTypeWithReference */ + float|(B&A) &$paramA, + /* testDNFTypeWithSpreadOperator */ + string|(B&D) ...$paramB +) {} + + +$closureWithParamType = function ( /* testDNFTypeClosureParamIllegalNullable */ ?(A&B)|bool $string) {}; + +/* testParensOwnerClosureAmpersandInDefaultValue */ +$closureWithReturnType = function ($string = NONSENSE & FAKE) /* testDNFTypeClosureReturn */ : (\Package\MyA&PackageB)|null {}; + +/* testParensOwnerArrowDNFUsedWithin */ +$arrowWithParamType = fn ( + /* testDNFTypeArrowParam */ + int|(A&B&C)|array $param, + /* testParensNoOwnerAmpersandInDefaultValue */ ?int $int = (CONSTA & CONSTB )| CONST_C +) + /* testParensNoOwnerInArrowReturnExpression */ + => ($param & $foo ) | $int; + +$arrowWithReturnType = fn ($param) : /* testDNFTypeArrowReturnType */ int|(A&B) => $param * 10; + +$arrowWithParamReturnByRef = fn &( + /* testDNFTypeArrowParamWithReturnByRef */ + (A&B)|null $param +) => $param * 10; + +function InvalidSyntaxes( + /* testDNFTypeParamIllegalUnnecessaryParens */ + (A&B) $parensNotNeeded, + + /* testDNFTypeParamIllegalIntersectUnionReversed */ + A&(B|D) $onlyIntersectAllowedWithinParensAndUnionOutside, + + /* testDNFTypeParamIllegalNestedParens */ + A|(B&(D|W)|null) $nestedParensNotAllowed, +) {} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.php new file mode 100644 index 00000000..d8393387 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.php @@ -0,0 +1,374 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class CreateParenthesisNestingMapDNFTypesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that parentheses when **not** used in a type declaration are correctly tokenized. + * + * @param string $testMarker The comment prefacing the target token. + * @param int|false $owner Optional. The parentheses owner or false when no parentheses owner is expected. + * + * @dataProvider dataNormalParentheses + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createParenthesisNestingMap + * + * @return void + */ + public function testNormalParentheses($testMarker, $owner=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_OPEN_PARENTHESIS (code)'); + + if ($owner !== false) { + $this->assertArrayHasKey('parenthesis_owner', $opener, 'Parenthesis owner is not set'); + $this->assertSame(($openPtr + $owner), $opener['parenthesis_owner'], 'Opener parenthesis owner is not the expected token'); + } else { + $this->assertArrayNotHasKey('parenthesis_owner', $opener, 'Parenthesis owner is set'); + } + + $this->assertArrayHasKey('parenthesis_opener', $opener, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $opener, 'Parenthesis closer is not set'); + $this->assertSame($openPtr, $opener['parenthesis_opener'], 'Parenthesis opener is not the expected token'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_CLOSE_PARENTHESIS (code)'); + + if ($owner !== false) { + $this->assertArrayHasKey('parenthesis_owner', $closer, 'Parenthesis owner is not set'); + $this->assertSame(($openPtr + $owner), $closer['parenthesis_owner'], 'Closer parenthesis owner is not the expected token'); + } else { + $this->assertArrayNotHasKey('parenthesis_owner', $closer, 'Parenthesis owner is set'); + } + + $this->assertArrayHasKey('parenthesis_opener', $closer, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $closer, 'Parenthesis closer is not set'); + $this->assertSame($closePtr, $closer['parenthesis_closer'], 'Parenthesis closer is not the expected token'); + + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + $this->assertArrayHasKey('nested_parenthesis', $tokens[$i], "Nested parenthesis key not set on token $i ({$tokens[$i]['type']})"); + $this->assertArrayHasKey($openPtr, $tokens[$i]['nested_parenthesis'], 'Nested parenthesis is missing target parentheses set'); + $this->assertSame($closePtr, $tokens[$i]['nested_parenthesis'][$openPtr], 'Nested parenthesis closer not set correctly'); + } + + }//end testNormalParentheses() + + + /** + * Data provider. + * + * @see testNormalParentheses() + * + * @return array> + */ + public static function dataNormalParentheses() + { + // "Owner" offsets are relative to the open parenthesis. + return [ + 'parens without owner' => [ + 'testMarker' => '/* testParensNoOwner */', + ], + 'parens without owner in ternary then' => [ + 'testMarker' => '/* testParensNoOwnerInTernary */', + ], + 'parens without owner in short ternary' => [ + 'testMarker' => '/* testParensNoOwnerInShortTernary */', + ], + 'parens with owner: function; & in default value' => [ + 'testMarker' => '/* testParensOwnerFunctionAmpersandInDefaultValue */', + 'owner' => -3, + ], + 'parens with owner: closure; param declared by & ref' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandParamRef */', + 'owner' => -1, + ], + 'parens with owner: if' => [ + 'testMarker' => '/* testParensOwnerIf */', + 'owner' => -2, + ], + 'parens without owner in if condition' => [ + 'testMarker' => '/* testParensNoOwnerInIfCondition */', + ], + 'parens with owner: for' => [ + 'testMarker' => '/* testParensOwnerFor */', + 'owner' => -2, + ], + 'parens without owner in for condition' => [ + 'testMarker' => '/* testParensNoOwnerInForCondition */', + ], + 'parens with owner: match' => [ + 'testMarker' => '/* testParensOwnerMatch */', + 'owner' => -1, + ], + 'parens with owner: array' => [ + 'testMarker' => '/* testParensOwnerArray */', + 'owner' => -2, + ], + 'parens without owner in array; function call with & in callable' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithAmpersandInCallable */', + ], + 'parens with owner: fn; & in return value' => [ + 'testMarker' => '/* testParensOwnerArrowFn */', + 'owner' => -1, + ], + 'parens with owner: list with reference vars' => [ + 'testMarker' => '/* testParensOwnerListWithRefVars */', + 'owner' => -1, + ], + 'parens without owner, function call with DNF look-a-like param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */', + ], + + 'parens without owner in OO const default value' => [ + 'testMarker' => '/* testParensNoOwnerOOConstDefaultValue */', + ], + 'parens without owner in property default 1' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue1 */', + ], + 'parens without owner in property default 2' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue2 */', + ], + 'parens without owner in param default value' => [ + 'testMarker' => '/* testParensNoOwnerParamDefaultValue */', + ], + 'parens without owner in return statement 1' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue1 */', + ], + 'parens without owner in return statement 2' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue2 */', + ], + 'parens without owner in return statement 3' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue3 */', + ], + 'parens with owner: closure; & in default value' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandInDefaultValue */', + 'owner' => -2, + ], + 'parens with owner: fn; dnf used within' => [ + 'testMarker' => '/* testParensOwnerArrowDNFUsedWithin */', + 'owner' => -2, + ], + 'parens without owner: default value for param in arrow function' => [ + 'testMarker' => '/* testParensNoOwnerAmpersandInDefaultValue */', + ], + 'parens without owner in arrow function return expression' => [ + 'testMarker' => '/* testParensNoOwnerInArrowReturnExpression */', + ], + ]; + + }//end dataNormalParentheses() + + + /** + * Test that parentheses when used in a DNF type declaration are correctly tokenized. + * + * Includes verifying that: + * - the tokens between the parentheses all have a "nested_parenthesis" key. + * - all ampersands between the parentheses are tokenized as T_TYPE_INTERSECTION. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataDNFTypeParentheses + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createParenthesisNestingMap + * + * @return void + */ + public function testDNFTypeParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_TYPE_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_TYPE_OPEN_PARENTHESIS (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $opener, 'Parenthesis owner is set'); + $this->assertArrayHasKey('parenthesis_opener', $opener, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $opener, 'Parenthesis closer is not set'); + $this->assertSame($openPtr, $opener['parenthesis_opener'], 'Parenthesis opener is not the expected token'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_TYPE_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_TYPE_CLOSE_PARENTHESIS (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $closer, 'Parenthesis owner is set'); + $this->assertArrayHasKey('parenthesis_opener', $closer, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $closer, 'Parenthesis closer is not set'); + $this->assertSame($closePtr, $closer['parenthesis_closer'], 'Parenthesis closer is not the expected token'); + + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + $this->assertArrayHasKey('nested_parenthesis', $tokens[$i], "Nested parenthesis key not set on token $i ({$tokens[$i]['type']})"); + $this->assertArrayHasKey($openPtr, $tokens[$i]['nested_parenthesis'], 'Nested parenthesis is missing target parentheses set'); + $this->assertSame($closePtr, $tokens[$i]['nested_parenthesis'][$openPtr], 'Nested parenthesis closer not set correctly'); + }//end for + + }//end testDNFTypeParentheses() + + + /** + * Data provider. + * + * @see testDNFTypeParentheses() + * + * @return array> + */ + public static function dataDNFTypeParentheses() + { + return [ + 'OO const type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstUnqualifiedClasses */', + ], + 'OO const type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypeOOConstReverseModifierOrder */', + ], + 'OO const type: multi-dnf part 1' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti1 */', + ], + 'OO const type: multi-dnf part 2' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti2 */', + ], + 'OO const type: multi-dnf part 3' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti3 */', + ], + 'OO const type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeOOConstNamespaceRelative */', + ], + 'OO const type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstPartiallyQualified */', + ], + 'OO const type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstFullyQualified */', + ], + + 'OO property type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyUnqualifiedClasses */', + ], + 'OO property type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypePropertyReverseModifierOrder */', + ], + 'OO property type: multi-dnf namespace relative classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiNamespaceRelative */', + ], + 'OO property type: multi-dnf partially qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiPartiallyQualified */', + ], + 'OO property type: multi-dnf fully qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiFullyQualified */', + ], + + 'OO property type: multi-dnf with readonly keyword 1' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword1 */', + ], + 'OO property type: multi-dnf with readonly keyword 2' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword2 */', + ], + 'OO property type: with static and readonly keywords' => [ + 'testMarker' => '/* testDNFTypePropertyWithStaticAndReadOnlyKeywords */', + ], + 'OO property type: with only static keyword' => [ + 'testMarker' => '/* testDNFTypePropertyWithOnlyStaticKeyword */', + ], + 'OO method param type: first param' => [ + 'testMarker' => '/* testDNFTypeParam1WithAttribute */', + ], + 'OO method param type: second param, first DNF' => [ + 'testMarker' => '/* testDNFTypeParam2 */', + ], + 'OO method param type: second param, second DNF' => [ + 'testMarker' => '/* testDNFTypeParam3 */', + ], + 'OO method param type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeParamNamespaceRelative */', + ], + 'OO method param type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamPartiallyQualified */', + ], + 'OO method param type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamFullyQualified */', + ], + 'Constructor property promotion with multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion1 */', + ], + 'Constructor property promotion with multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion2 */', + ], + 'OO method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeReturnType1 */', + ], + 'OO method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeReturnType2 */', + ], + 'OO abstract method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType1 */', + ], + 'OO abstract method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType2 */', + ], + 'OO method return type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeReturnTypeNamespaceRelative */', + ], + 'OO method return type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnPartiallyQualified */', + ], + 'OO method return type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnFullyQualified */', + ], + 'function param type: with reference' => [ + 'testMarker' => '/* testDNFTypeWithReference */', + ], + 'function param type: with spread' => [ + 'testMarker' => '/* testDNFTypeWithSpreadOperator */', + ], + 'closure param type: with illegal nullable' => [ + 'testMarker' => '/* testDNFTypeClosureParamIllegalNullable */', + ], + 'closure return type' => [ + 'testMarker' => '/* testDNFTypeClosureReturn */', + ], + 'arrow function param type' => [ + 'testMarker' => '/* testDNFTypeArrowParam */', + ], + 'arrow function return type' => [ + 'testMarker' => '/* testDNFTypeArrowReturnType */', + ], + 'arrow function param type with return by ref' => [ + 'testMarker' => '/* testDNFTypeArrowParamWithReturnByRef */', + ], + + 'illegal syntax: unnecessary parentheses (no union)' => [ + 'testMarker' => '/* testDNFTypeParamIllegalUnnecessaryParens */', + ], + 'illegal syntax: union within parentheses, intersect outside' => [ + 'testMarker' => '/* testDNFTypeParamIllegalIntersectUnionReversed */', + ], + 'illegal syntax: nested parentheses' => [ + 'testMarker' => '/* testDNFTypeParamIllegalNestedParens */', + ], + ]; + + }//end dataDNFTypeParentheses() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.inc new file mode 100644 index 00000000..a800980b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.inc @@ -0,0 +1,43 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Heredoc/nowdoc closer token test. + * + * @requires PHP 7.3 + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapHeredocNowdocCloserTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that leading (indent) whitespace in a heredoc/nowdoc closer token get the tab replacement treatment. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $expected Expectations for the token array. + * + * @dataProvider dataHeredocNowdocCloserTabReplacement + * + * @return void + */ + public function testHeredocNowdocCloserTabReplacement($testMarker, $expected) + { + $tokens = $this->phpcsFile->getTokens(); + + $closer = $this->getTargetToken($testMarker, [T_END_HEREDOC, T_END_NOWDOC]); + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$closer], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$closer], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$closer][$key], "Value for key $key does not match expectation."); + } + + }//end testHeredocNowdocCloserTabReplacement() + + + /** + * Data provider. + * + * @see testHeredocNowdocCloserTabReplacement() + * + * @return array>> + */ + public static function dataHeredocNowdocCloserTabReplacement() + { + return [ + 'Heredoc closer without indent' => [ + 'testMarker' => '/* testHeredocCloserNoIndent */', + 'expected' => [ + 'length' => 3, + 'content' => 'EOD', + 'orig_content' => null, + ], + ], + 'Nowdoc closer without indent' => [ + 'testMarker' => '/* testNowdocCloserNoIndent */', + 'expected' => [ + 'length' => 3, + 'content' => 'EOD', + 'orig_content' => null, + ], + ], + 'Heredoc closer with indent, spaces' => [ + 'testMarker' => '/* testHeredocCloserSpaceIndent */', + 'expected' => [ + 'length' => 7, + 'content' => ' END', + 'orig_content' => null, + ], + ], + 'Nowdoc closer with indent, spaces' => [ + 'testMarker' => '/* testNowdocCloserSpaceIndent */', + 'expected' => [ + 'length' => 8, + 'content' => ' END', + 'orig_content' => null, + ], + ], + 'Heredoc closer with indent, tabs' => [ + 'testMarker' => '/* testHeredocCloserTabIndent */', + 'expected' => [ + 'length' => 8, + 'content' => ' END', + 'orig_content' => ' END', + ], + ], + 'Nowdoc closer with indent, tabs' => [ + 'testMarker' => '/* testNowdocCloserTabIndent */', + 'expected' => [ + 'length' => 7, + 'content' => ' END', + 'orig_content' => ' END', + ], + ], + ]; + + }//end dataHeredocNowdocCloserTabReplacement() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocOpenerTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocOpenerTest.inc new file mode 100644 index 00000000..dc2b2f2d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocOpenerTest.inc @@ -0,0 +1,31 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Heredoc/nowdoc opener token test. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapHeredocNowdocOpenerTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that spaces/tabs in a heredoc/nowdoc opener token get the tab replacement treatment. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $expected Expectations for the token array. + * + * @dataProvider dataHeredocNowdocOpenerTabReplacement + * + * @return void + */ + public function testHeredocNowdocOpenerTabReplacement($testMarker, $expected) + { + $tokens = $this->phpcsFile->getTokens(); + $opener = $this->getTargetToken($testMarker, [T_START_HEREDOC, T_START_NOWDOC]); + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$opener], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$opener], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$opener][$key], "Value for key $key does not match expectation."); + } + + }//end testHeredocNowdocOpenerTabReplacement() + + + /** + * Data provider. + * + * @see testHeredocNowdocOpenerTabReplacement() + * + * @return array>> + */ + public static function dataHeredocNowdocOpenerTabReplacement() + { + return [ + 'Heredoc opener without space' => [ + 'testMarker' => '/* testHeredocOpenerNoSpace */', + 'expected' => [ + 'length' => 6, + 'content' => '<< null, + ], + ], + 'Nowdoc opener without space' => [ + 'testMarker' => '/* testNowdocOpenerNoSpace */', + 'expected' => [ + 'length' => 8, + 'content' => "<<<'EOD' +", + 'orig_content' => null, + ], + ], + 'Heredoc opener with space(s)' => [ + 'testMarker' => '/* testHeredocOpenerHasSpace */', + 'expected' => [ + 'length' => 7, + 'content' => '<<< END +', + 'orig_content' => null, + ], + ], + 'Nowdoc opener with space(s)' => [ + 'testMarker' => '/* testNowdocOpenerHasSpace */', + 'expected' => [ + 'length' => 21, + 'content' => "<<< 'END' +", + 'orig_content' => null, + ], + ], + 'Heredoc opener with tab(s)' => [ + 'testMarker' => '/* testHeredocOpenerHasTab */', + 'expected' => [ + 'length' => 18, + 'content' => '<<< "END" +', + 'orig_content' => '<<< "END" +', + ], + ], + 'Nowdoc opener with tab(s)' => [ + 'testMarker' => '/* testNowdocOpenerHasTab */', + 'expected' => [ + 'length' => 11, + 'content' => "<<< 'END' +", + 'orig_content' => "<<< 'END' +", + ], + ], + ]; + + }//end dataHeredocNowdocOpenerTabReplacement() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapTabWidth0Test.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapTabWidth0Test.php new file mode 100644 index 00000000..fd47bf7d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapTabWidth0Test.php @@ -0,0 +1,107 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 0, means no tab replacement will take place. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapTabWidth0Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 0; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 2, + 'content' => ' ', + 'orig_content' => null, + ], + 'Mixed tab/space indentation' => [ + 'length' => 3, + 'content' => ' ', + 'orig_content' => null, + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => null, + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 24, + 'content' => '"tab $between each word"', + 'orig_content' => null, + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 15, + 'content' => 'tab separated +', + 'orig_content' => null, + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 27, + 'content' => 'tab between each word +', + 'orig_content' => null, + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 20, + 'content' => "'tab separated'", + 'orig_content' => null, + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 31, + 'content' => '"tab $between each word"', + 'orig_content' => null, + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => null, + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 52, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => null, + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 45, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => null, + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => null, + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapYieldFromTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapYieldFromTest.inc new file mode 100644 index 00000000..59365dd5 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapYieldFromTest.inc @@ -0,0 +1,15 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Yield from token test. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapYieldFromTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that spaces/tabs in "yield from" tokens get the tab replacement treatment. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $expected Expectations for the token array. + * @param string $content Optional. The test token content to search for. + * Defaults to null. + * + * @dataProvider dataYieldFromTabReplacement + * + * @return void + */ + public function testYieldFromTabReplacement($testMarker, $expected, $content=null) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD_FROM], $content); + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation."); + } + + }//end testYieldFromTabReplacement() + + + /** + * Data provider. + * + * @see testYieldFromTabReplacement() + * + * @return array>> + */ + public static function dataYieldFromTabReplacement() + { + return [ + 'Yield from, single line, single space' => [ + 'testMarker' => '/* testYieldFromHasSingleSpace */', + 'expected' => [ + 'length' => 10, + 'content' => 'yield from', + 'orig_content' => null, + ], + ], + 'Yield from, single line, multiple spaces' => [ + 'testMarker' => '/* testYieldFromHasMultiSpace */', + 'expected' => [ + 'length' => 14, + 'content' => 'yield from', + 'orig_content' => null, + ], + ], + 'Yield from, single line, has tabs' => [ + 'testMarker' => '/* testYieldFromHasTabs */', + 'expected' => [ + 'length' => 16, + 'content' => 'yield from', + 'orig_content' => 'yield from', + ], + ], + 'Yield from, single line, mix of tabs and spaces' => [ + 'testMarker' => '/* testYieldFromMixedTabsSpaces */', + 'expected' => [ + 'length' => 20, + 'content' => 'Yield From', + 'orig_content' => 'Yield From', + ], + ], + ]; + + }//end dataYieldFromTabReplacement() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.inc new file mode 100644 index 00000000..6d8adfcb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.inc @@ -0,0 +1,58 @@ + 10); + +/* testArrayWithComment */ +$var = Array /*comment*/ (1 => 10); + +/* testNestingArray */ +$var = array( + /* testNestedArray */ + array( + 'key' => 'value', + + /* testClosureReturnType */ + 'closure' => function($a) use($global) : Array {}, + ), +); + +/* testFunctionDeclarationParamType */ +function typedParam(array $a) {} + +/* testFunctionDeclarationReturnType */ +function returnType($a) : int|array|null {} + +class Bar { + /* testClassConst */ + const ARRAY = []; + + /* testClassMethod */ + public function array() {} + + /* testOOConstType */ + const array /* testTypedOOConstName */ ARRAY = /* testOOConstDefault */ array(); + + /* testOOPropertyType */ + protected array $property; +} + +class DNFTypes { + /* testOOConstDNFType */ + const (A&B)|array|(C&D) NAME = []; + + /* testOOPropertyDNFType */ + protected (A&B)|ARRAY|null $property; + + /* testFunctionDeclarationParamDNFType */ + public function name(null|array|(A&B) $param) { + /* testClosureDeclarationParamDNFType */ + $cl = function ( array|(A&B) $param) {}; + + /* testArrowDeclarationReturnDNFType */ + $arrow = fn($a): (A&B)|Array => new $a; + } +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.php new file mode 100644 index 00000000..e811211f --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.php @@ -0,0 +1,212 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class CreateTokenMapArrayParenthesesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the array keyword is correctly tokenized as `T_ARRAY`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap + * + * @return void + */ + public function testArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame(T_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (code)'); + + $this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set'); + + }//end testArrayKeyword() + + + /** + * Data provider. + * + * @see testArrayKeyword() + * + * @return array> + */ + public static function dataArrayKeyword() + { + return [ + 'empty array' => [ + 'testMarker' => '/* testEmptyArray */', + ], + 'array with space before parenthesis' => [ + 'testMarker' => '/* testArrayWithSpace */', + ], + 'array with comment before parenthesis' => [ + 'testMarker' => '/* testArrayWithComment */', + 'testContent' => 'Array', + ], + 'nested: outer array' => [ + 'testMarker' => '/* testNestingArray */', + ], + 'nested: inner array' => [ + 'testMarker' => '/* testNestedArray */', + ], + 'OO constant default value' => [ + 'testMarker' => '/* testOOConstDefault */', + ], + ]; + + }//end dataArrayKeyword() + + + /** + * Test that the array keyword when used in a type declaration is correctly tokenized as `T_STRING`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayType + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap + * + * @return void + */ + public function testArrayType($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testArrayType() + + + /** + * Data provider. + * + * @see testArrayType() + * + * @return array> + */ + public static function dataArrayType() + { + return [ + 'closure return type' => [ + 'testMarker' => '/* testClosureReturnType */', + 'testContent' => 'Array', + ], + 'function param type' => [ + 'testMarker' => '/* testFunctionDeclarationParamType */', + ], + 'function union return type' => [ + 'testMarker' => '/* testFunctionDeclarationReturnType */', + ], + 'OO constant type' => [ + 'testMarker' => '/* testOOConstType */', + ], + 'OO property type' => [ + 'testMarker' => '/* testOOPropertyType */', + ], + + 'OO constant DNF type' => [ + 'testMarker' => '/* testOOConstDNFType */', + ], + 'OO property DNF type' => [ + 'testMarker' => '/* testOOPropertyDNFType */', + 'testContent' => 'ARRAY', + ], + 'function param DNF type' => [ + 'testMarker' => '/* testFunctionDeclarationParamDNFType */', + ], + 'closure param DNF type' => [ + 'testMarker' => '/* testClosureDeclarationParamDNFType */', + ], + 'arrow return DNF type' => [ + 'testMarker' => '/* testArrowDeclarationReturnDNFType */', + 'testContent' => 'Array', + ], + ]; + + }//end dataArrayType() + + + /** + * Verify that the retokenization of `T_ARRAY` tokens to `T_STRING` is handled correctly + * for tokens with the contents 'array' which aren't in actual fact the array keyword. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap + * + * @return void + */ + public function testNotArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testNotArrayKeyword() + + + /** + * Data provider. + * + * @see testNotArrayKeyword() + * + * @return array> + */ + public static function dataNotArrayKeyword() + { + return [ + 'class-constant-name' => [ + 'testMarker' => '/* testClassConst */', + 'testContent' => 'ARRAY', + ], + 'class-method-name' => [ + 'testMarker' => '/* testClassMethod */', + ], + 'class-constant-name-after-type' => [ + 'testMarker' => '/* testTypedOOConstName */', + 'testContent' => 'ARRAY', + ], + ]; + + }//end dataNotArrayKeyword() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc new file mode 100644 index 00000000..5a0debcd --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc @@ -0,0 +1,132 @@ + $num) + return bar( + baz( + "foobarbaz" + ) + ); + break; +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php new file mode 100644 index 00000000..ca70a34c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php @@ -0,0 +1,271 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapCaseKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that enum "case" tokens does not get scope indexes. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataEnumCases + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testEnumCases($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCase = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$enumCase]; + + // Make sure we're looking at the right token. + $this->assertSame(T_ENUM_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (code)'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + + }//end testEnumCases() + + + /** + * Data provider. + * + * @see testEnumCases() + * + * @return array> + */ + public static function dataEnumCases() + { + return [ + 'enum case, no value' => ['/* testPureEnumCase */'], + 'enum case, integer value' => ['/* testBackingIntegerEnumCase */'], + 'enum case, string value' => ['/* testBackingStringEnumCase */'], + 'enum case, integer value in more complex enum' => ['/* testEnumCaseInComplexEnum */'], + 'enum case, keyword in mixed case' => ['/* testEnumCaseIsCaseInsensitive */'], + 'enum case, after switch statement' => ['/* testEnumCaseAfterSwitch */'], + 'enum case, after switch statement using alternative syntax' => ['/* testEnumCaseAfterSwitchWithEndSwitch */'], + ]; + + }//end dataEnumCases() + + + /** + * Test that switch "case" tokens do get the scope indexes. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedTokens The expected token codes for the scope opener/closer. + * @param string|null $testCloserMarker Optional. The comment which prefaces the scope closer if different + * from the test marker. + * + * @dataProvider dataNotEnumCases + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testNotEnumCases($testMarker, $expectedTokens, $testCloserMarker=null) + { + $tokens = $this->phpcsFile->getTokens(); + $caseIndex = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$caseIndex]; + + $scopeCloserMarker = $testMarker; + if (isset($testCloserMarker) === true) { + $scopeCloserMarker = $testCloserMarker; + } + + $expectedScopeCondition = $caseIndex; + $expectedScopeOpener = $this->getTargetToken($testMarker, $expectedTokens['scope_opener']); + $expectedScopeCloser = $this->getTargetToken($scopeCloserMarker, $expectedTokens['scope_closer']); + + // Make sure we're looking at the right token. + $this->assertSame(T_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (code)'); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_CASE, found %s.', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s.', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s.', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testNotEnumCases() + + + /** + * Data provider. + * + * @see testNotEnumCases() + * + * @return array>> + */ + public static function dataNotEnumCases() + { + return [ + 'switch case with constant, semicolon condition end' => [ + 'testMarker' => '/* testCaseWithSemicolonIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_SEMICOLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + ], + 'switch case with constant, colon condition end' => [ + 'testMarker' => '/* testCaseWithConstantIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, comparison' => [ + 'testMarker' => '/* testCaseWithConstantAndIdenticalIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, assignment' => [ + 'testMarker' => '/* testCaseWithAssignmentToConstantIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, keyword in mixed case' => [ + 'testMarker' => '/* testIsNotEnumCaseIsCaseInsensitive */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case, body in curlies declares enum' => [ + 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1 */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1CloserMarker */', + ], + 'switch case, body after semicolon declares enum' => [ + 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2 */', + 'expectedTokens' => [ + 'scope_opener' => T_SEMICOLON, + 'scope_closer' => T_BREAK, + ], + 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2CloserMarker */', + ], + 'switch case, shared closer with switch' => [ + 'testMarker' => '/* testSwitchCaseScopeCloserSharedWithSwitch */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + ], + 'switch case, nested inline if/elseif/else with and without braces' => [ + 'testMarker' => '/* testSwitchCaseNestedIfWithAndWithoutBraces */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_BREAK, + ], + ], + 'switch case, nested inline if' => [ + 'testMarker' => '/* testSwitchCaseNestedInlineIfWithMoreThanThreeLines */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_BREAK, + ], + ], + ]; + + }//end dataNotEnumCases() + + + /** + * Test that a "case" keyword which is not a switch or enum case, does not get the scope indexes. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataKeywordAsEnumCaseNameShouldBeString + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testKeywordAsEnumCaseNameShouldBeString($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCaseName = $this->getTargetToken($testMarker, [T_STRING, T_INTERFACE, T_TRAIT, T_ENUM, T_FUNCTION, T_FALSE, T_DEFAULT, T_ARRAY]); + $tokenArray = $tokens[$enumCaseName]; + + // Make sure we're looking at the right token. + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + + }//end testKeywordAsEnumCaseNameShouldBeString() + + + /** + * Data provider. + * + * @see testKeywordAsEnumCaseNameShouldBeString() + * + * @return array> + */ + public static function dataKeywordAsEnumCaseNameShouldBeString() + { + return [ + '"interface" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString1 */'], + '"trait" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString2 */'], + '"enum" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString3 */'], + '"function" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString4 */'], + '"false" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString5 */'], + '"default" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString6 */'], + '"array" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString7 */'], + ]; + + }//end dataKeywordAsEnumCaseNameShouldBeString() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.inc new file mode 100644 index 00000000..c98f518c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.inc @@ -0,0 +1,231 @@ + 1, + 2 => 2, + /* testSimpleMatchDefault */ + default => 'default', + }; +} + +function switchWithDefault($i) { + switch ($i) { + case 1: + return 1; + case 2: + return 2; + /* testSimpleSwitchDefault */ + default: + return 'default'; + } +} + +function switchWithDefaultAndCurlies($i) { + switch ($i) { + case 1: + return 1; + case 2: + return 2; + /* testSimpleSwitchDefaultWithCurlies */ + default: /* testSimpleSwitchDefaultWithCurliesScopeOpener */ { + /* testSimpleSwitchDefaultWithCurliesConditionStop */ + return 'default'; + /* testSimpleSwitchDefaultWithCurliesScopeCloser */ + } + } +} + +function matchWithDefaultInSwitch() { + switch ($something) { + case 'foo': + $var = [1, 2, 3]; + $var = match ($i) { + 1 => 1, + /* testMatchDefaultNestedInSwitchCase1 */ + default => 'default', + }; + continue; + + case 'bar' : + $i = callMe($a, $b); + return match ($i) { + 1 => 1, + /* testMatchDefaultNestedInSwitchCase2 */ + default => 'default', + }; + + /* testSwitchDefault */ + default; + echo 'something', match ($i) { + 1, => 1, + /* testMatchDefaultNestedInSwitchDefault */ + default, => 'default', + }; + /* testSwitchDefaultCloserMarker */ + break; + } +} + +function switchWithDefaultInMatch() { + $x = match ($y) { + 5, 8 => function($z) { + switch($z) { + case 'a'; + $var = [1, 2, 3]; + return 'a'; + /* testSwitchDefaultNestedInMatchCase */ + default: + $var = [1, 2, 3]; + return 'default1'; + } + }, + /* testMatchDefault */ + default => function($z) { + switch($z) { + case 'a': + $i = callMe($a, $b); + return 'b'; + /* testSwitchDefaultNestedInMatchDefault */ + default: + $i = callMe($a, $b); + return 'default2'; + } + } + }; +} + +function switchAndDefaultSharingScopeCloser($i) { + switch ($i): + /* testSwitchAndDefaultSharingScopeCloser */ + default: + echo 'one'; + /* testSwitchAndDefaultSharingScopeCloserScopeCloser */ + endswitch; +} + +function switchDefaultNestedIfWithAndWithoutBraces($i, $foo, $baz) { + switch ($i) { + /* testSwitchDefaultNestedIfWithAndWithoutBraces */ + default: + if ($foo) { + return true; + } elseif ($baz) + return true; + else { + echo 'else'; + } + /* testSwitchDefaultNestedIfWithAndWithoutBracesScopeCloser */ + break; + } +} + +function shortArrayWithConstantKey() { + $arr = [ + /* testClassConstantAsShortArrayKey */ + SomeClass::DEFAULT => 1, + /* testClassPropertyAsShortArrayKey */ + SomeClass->DEFAULT => 1, + /* testNamespacedConstantAsShortArrayKey */ + // Intentional parse error PHP < 8.0. Reserved keyword used as namespaced constant. + SomeNamespace\DEFAULT => 1, + /* testFQNGlobalConstantAsShortArrayKey */ + // Intentional parse error in PHP < 8.0. Reserved keyword used as global constant. + \DEFAULT => 1, + ]; +} + +function longArrayWithConstantKey() { + $arr = array( + /* testClassConstantAsLongArrayKey */ + SomeClass::DEFAULT => 1, + ); +} + +function yieldWithConstantKey() { + /* testClassConstantAsYieldKey */ + yield SomeClass::DEFAULT => 1; +} + +function longArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchDefaultWithNestedLongArrayWithClassConstantKey */ + DEFAULT => array( + /* testClassConstantAsLongArrayKeyNestedInMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */ + DEFAULT => array( + /* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */ + SomeClass::DEFAULT => 1, + ), + }, + ), + }; +} + +function shortArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchDefaultWithNestedShortArrayWithClassConstantKey */ + DEFAULT => [ + /* testClassConstantAsShortArrayKeyNestedInMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */ + DEFAULT => [ + /* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */ + SomeClass::DEFAULT => 1, + ], + }, + ], + }; +} + + +function longArrayWithConstantKeyWithNestedMatch() { + return array( + /* testClassConstantAsLongArrayKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultNestedInLongArray */ + DEFAULT => 'foo' + }, + ); +} + +function shortArrayWithConstantKeyWithNestedMatch() { + return [ + /* testClassConstantAsShortArrayKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultNestedInShortArray */ + DEFAULT => 'foo' + }, + ]; +} + +function switchWithConstantNonDefault($i) { + switch ($i) { + /* testClassConstantInSwitchCase */ + case SomeClass::DEFAULT: + return 1; + + /* testClassPropertyInSwitchCase */ + case SomeClass->DEFAULT: + return 2; + + /* testNamespacedConstantInSwitchCase */ + // Intentional parse error PHP < 8.0. Reserved keyword used as constant. + case SomeNamespace\DEFAULT: + return 2; + + /* testNamespaceRelativeConstantInSwitchCase */ + // Intentional parse error PHP < 8.0. Reserved keyword used as global constant. + case namespace\DEFAULT: + return 2; + } +} + +class Foo { + /* testClassConstant */ + const DEFAULT = 'foo'; + + /* testMethodDeclaration */ + public function default() {} +} diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.php new file mode 100644 index 00000000..9b40fe10 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.php @@ -0,0 +1,487 @@ + + * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapDefaultKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + /** + * Condition stop tokens when `default` is used with curlies. + * + * @var array + */ + protected $conditionStopTokens = [ + T_BREAK, + T_CONTINUE, + T_EXIT, + T_GOTO, + T_RETURN, + T_THROW, + ]; + + + /** + * Test that match "default" tokens does not get scope indexes. + * + * Note: Cases and default structures within a match structure do *NOT* get case/default scope + * conditions, in contrast to case and default structures in switch control structures. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataMatchDefault + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testMatchDefault($testMarker, $testContent='default') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame( + T_MATCH_DEFAULT, + $tokenArray['code'], + sprintf('Token tokenized as %s, not T_MATCH_DEFAULT (code). Marker: %s.', $tokenArray['type'], $testMarker) + ); + + $this->assertArrayNotHasKey( + 'scope_condition', + $tokenArray, + sprintf('Scope condition is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_opener', + $tokenArray, + sprintf('Scope opener is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_closer', + $tokenArray, + sprintf('Scope closer is set. Marker: %s.', $testMarker) + ); + + }//end testMatchDefault() + + + /** + * Data provider. + * + * @see testMatchDefault() + * + * @return array> + */ + public static function dataMatchDefault() + { + return [ + 'simple_match_default' => [ + 'testMarker' => '/* testSimpleMatchDefault */', + ], + 'match_default_in_switch_case_1' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase1 */', + ], + 'match_default_in_switch_case_2' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase2 */', + ], + 'match_default_in_switch_default' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchDefault */', + ], + 'match_default_containing_switch' => [ + 'testMarker' => '/* testMatchDefault */', + ], + + 'match_default_with_nested_long_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_long_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_long_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInLongArray */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_short_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInShortArray */', + 'testContent' => 'DEFAULT', + ], + ]; + + }//end dataMatchDefault() + + + /** + * Test that switch "default" tokens do get the scope indexes. + * + * Note: Cases and default structures within a switch control structure *do* get case/default scope + * conditions. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $openerMarker The comment prefacing the scope opener token. + * @param string $closerMarker The comment prefacing the scope closer token. + * @param string|null $conditionStopMarker The expected offset in relation to the testMarker, after which tokens stop + * having T_DEFAULT as a scope condition. + * @param string $testContent The token content to look for. + * @param bool $sharedScopeCloser Whether to skip checking for the `scope_condition` of the + * scope closer. Needed when the default and switch + * structures share a scope closer. See + * https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/810. + * + * @dataProvider dataSwitchDefault + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testSwitchDefault($testMarker, $openerMarker, $closerMarker, $conditionStopMarker=null, $testContent='default', $sharedScopeCloser=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + $expectedScopeOpener = $this->getTargetToken($openerMarker, [T_COLON, T_OPEN_CURLY_BRACKET, T_SEMICOLON]); + $expectedScopeCloser = $this->getTargetToken($closerMarker, [T_BREAK, T_CLOSE_CURLY_BRACKET, T_RETURN, T_ENDSWITCH]); + + // Make sure we're looking at the right token. + $this->assertSame( + T_DEFAULT, + $tokenArray['code'], + sprintf('Token tokenized as %s, not T_DEFAULT (code). Marker: %s.', $tokenArray['type'], $testMarker) + ); + + $this->assertArrayHasKey( + 'scope_condition', + $tokenArray, + sprintf('Scope condition is not set. Marker: %s.', $testMarker) + ); + $this->assertArrayHasKey( + 'scope_opener', + $tokenArray, + sprintf('Scope opener is not set. Marker: %s.', $testMarker) + ); + $this->assertArrayHasKey( + 'scope_closer', + $tokenArray, + sprintf('Scope closer is not set. Marker: %s.', $testMarker) + ); + $this->assertSame( + $token, + $tokenArray['scope_condition'], + sprintf('Scope condition is not the T_DEFAULT token. Marker: %s.', $testMarker) + ); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf('Scope opener of the T_DEFAULT token incorrect. Marker: %s.', $testMarker) + ); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf('Scope closer of the T_DEFAULT token incorrect. Marker: %s.', $testMarker) + ); + + $opener = $tokenArray['scope_opener']; + $this->assertArrayHasKey( + 'scope_condition', + $tokens[$opener], + sprintf('Opener scope condition is not set. Marker: %s.', $openerMarker) + ); + $this->assertArrayHasKey( + 'scope_opener', + $tokens[$opener], + sprintf('Opener scope opener is not set. Marker: %s.', $openerMarker) + ); + $this->assertArrayHasKey( + 'scope_closer', + $tokens[$opener], + sprintf('Opener scope closer is not set. Marker: %s.', $openerMarker) + ); + $this->assertSame( + $token, + $tokens[$opener]['scope_condition'], + sprintf('Opener scope condition is not the T_DEFAULT token. Marker: %s.', $openerMarker) + ); + $this->assertSame( + $expectedScopeOpener, + $tokens[$opener]['scope_opener'], + sprintf('T_DEFAULT opener scope opener token incorrect. Marker: %s.', $openerMarker) + ); + $this->assertSame( + $expectedScopeCloser, + $tokens[$opener]['scope_closer'], + sprintf('T_DEFAULT opener scope closer token incorrect. Marker: %s.', $openerMarker) + ); + + $closer = $expectedScopeCloser; + + if ($sharedScopeCloser === false) { + $closer = $tokenArray['scope_closer']; + $this->assertArrayHasKey( + 'scope_condition', + $tokens[$closer], + sprintf('Closer scope condition is not set. Marker: %s.', $closerMarker) + ); + $this->assertArrayHasKey( + 'scope_opener', + $tokens[$closer], + sprintf('Closer scope opener is not set. Marker: %s.', $closerMarker) + ); + $this->assertArrayHasKey( + 'scope_closer', + $tokens[$closer], + sprintf('Closer scope closer is not set. Marker: %s.', $closerMarker) + ); + $this->assertSame( + $token, + $tokens[$closer]['scope_condition'], + sprintf('Closer scope condition is not the T_DEFAULT token. Marker: %s.', $closerMarker) + ); + $this->assertSame( + $expectedScopeOpener, + $tokens[$closer]['scope_opener'], + sprintf('T_DEFAULT closer scope opener token incorrect. Marker: %s.', $closerMarker) + ); + $this->assertSame( + $expectedScopeCloser, + $tokens[$closer]['scope_closer'], + sprintf('T_DEFAULT closer scope closer token incorrect. Marker: %s.', $closerMarker) + ); + }//end if + + if (($opener + 1) !== $closer) { + $end = $closer; + if (isset($conditionStopMarker) === true) { + $end = ( $this->getTargetToken($conditionStopMarker, $this->conditionStopTokens) + 1); + } + + for ($i = ($opener + 1); $i < $end; $i++) { + $this->assertArrayHasKey( + $token, + $tokens[$i]['conditions'], + sprintf('T_DEFAULT condition not added for token belonging to the T_DEFAULT structure. Marker: %s.', $testMarker) + ); + } + }//end if + + }//end testSwitchDefault() + + + /** + * Data provider. + * + * @see testSwitchDefault() + * + * @return array> + */ + public static function dataSwitchDefault() + { + return [ + 'simple_switch_default' => [ + 'testMarker' => '/* testSimpleSwitchDefault */', + 'openerMarker' => '/* testSimpleSwitchDefault */', + 'closerMarker' => '/* testSimpleSwitchDefault */', + ], + 'simple_switch_default_with_curlies' => [ + // For a default structure with curly braces, the scope opener + // will be the open curly and the closer the close curly. + // However, scope conditions will not be set for open to close, + // but only for the open token up to the "break/return/continue" etc. + 'testMarker' => '/* testSimpleSwitchDefaultWithCurlies */', + 'openerMarker' => '/* testSimpleSwitchDefaultWithCurliesScopeOpener */', + 'closerMarker' => '/* testSimpleSwitchDefaultWithCurliesScopeCloser */', + 'conditionStopMarker' => '/* testSimpleSwitchDefaultWithCurliesConditionStop */', + ], + 'switch_default_toplevel' => [ + 'testMarker' => '/* testSwitchDefault */', + 'openerMarker' => '/* testSwitchDefault */', + 'closerMarker' => '/* testSwitchDefaultCloserMarker */', + ], + 'switch_default_nested_in_match_case' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'openerMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'closerMarker' => '/* testSwitchDefaultNestedInMatchCase */', + ], + 'switch_default_nested_in_match_default' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'openerMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'closerMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + ], + 'switch_and_default_sharing_scope_closer' => [ + 'testMarker' => '/* testSwitchAndDefaultSharingScopeCloser */', + 'openerMarker' => '/* testSwitchAndDefaultSharingScopeCloser */', + 'closerMarker' => '/* testSwitchAndDefaultSharingScopeCloserScopeCloser */', + 'conditionStopMarker' => null, + 'testContent' => 'default', + 'sharedScopeCloser' => true, + ], + 'switch_and_default_with_nested_if_with_and_without_braces' => [ + 'testMarker' => '/* testSwitchDefaultNestedIfWithAndWithoutBraces */', + 'openerMarker' => '/* testSwitchDefaultNestedIfWithAndWithoutBraces */', + 'closerMarker' => '/* testSwitchDefaultNestedIfWithAndWithoutBracesScopeCloser */', + ], + ]; + + }//end dataSwitchDefault() + + + /** + * Test that a "default" keyword which is not a switch or match default, does not get the scope indexes. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotDefaultKeyword + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame( + T_STRING, + $tokenArray['code'], + sprintf('Token tokenized as %s, not T_STRING (code). Marker: %s.', $tokenArray['type'], $testMarker) + ); + + $this->assertArrayNotHasKey( + 'scope_condition', + $tokenArray, + sprintf('Scope condition is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_opener', + $tokenArray, + sprintf('Scope opener is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_closer', + $tokenArray, + sprintf('Scope closer is set. Marker: %s.', $testMarker) + ); + + }//end testNotDefaultKeyword() + + + /** + * Data provider. + * + * @see testNotDefaultKeyword() + * + * @return array> + */ + public static function dataNotDefaultKeyword() + { + return [ + 'class-constant-as-short-array-key' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKey */', + ], + 'class-property-as-short-array-key' => [ + 'testMarker' => '/* testClassPropertyAsShortArrayKey */', + ], + 'namespaced-constant-as-short-array-key' => [ + 'testMarker' => '/* testNamespacedConstantAsShortArrayKey */', + ], + 'fqn-global-constant-as-short-array-key' => [ + 'testMarker' => '/* testFQNGlobalConstantAsShortArrayKey */', + ], + 'class-constant-as-long-array-key' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKey */', + ], + 'class-constant-as-yield-key' => [ + 'testMarker' => '/* testClassConstantAsYieldKey */', + ], + + 'class-constant-as-long-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatch */', + ], + 'class-constant-as-long-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-short-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatch */', + ], + 'class-constant-as-short-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-long-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyWithNestedMatch */', + ], + 'class-constant-as-short-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyWithNestedMatch */', + ], + + 'class-constant-in-switch-case' => [ + 'testMarker' => '/* testClassConstantInSwitchCase */', + ], + 'class-property-in-switch-case' => [ + 'testMarker' => '/* testClassPropertyInSwitchCase */', + ], + 'namespaced-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespacedConstantInSwitchCase */', + ], + 'namespace-relative-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespaceRelativeConstantInSwitchCase */', + ], + + 'class-constant-declaration' => [ + 'testMarker' => '/* testClassConstant */', + ], + 'class-method-declaration' => [ + 'testMarker' => '/* testMethodDeclaration */', + 'testContent' => 'default', + ], + ]; + + }//end dataNotDefaultKeyword() + + + /** + * Test a specific edge case where a scope opener would be incorrectly set. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/3326 + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testIssue3326() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testClassConstant */', [T_SEMICOLON]); + $tokenArray = $tokens[$token]; + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + + }//end testIssue3326() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc new file mode 100644 index 00000000..e303c385 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc @@ -0,0 +1,13 @@ + + * @author Rodrigo Primo + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapIfKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + + /** + * Tests setting the scope for T_IF token with nested case statement missing break statement. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/497#ref-commit-fddc61a + * + * @covers \PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testIfElseWithNestedCaseMissingBreakSharedClosers() + { + + $tokens = $this->phpcsFile->getTokens(); + $ifTestMarker = '/* testIfElseWithNestedCaseMissingBreak */'; + $ifCloserTestMarker = '/* testIfElseWithNestedCaseMissingBreakCloser */'; + $ifTokenIndex = $this->getTargetToken($ifTestMarker, T_IF); + $tokenArray = $tokens[$ifTokenIndex]; + + $expectedScopeCondition = $ifTokenIndex; + $expectedScopeOpener = $this->getTargetToken($ifTestMarker, T_COLON); + $expectedScopeCloser = $this->getTargetToken($ifCloserTestMarker, T_ELSE); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_IF, found %s', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testIfElseWithNestedCaseMissingBreakSharedClosers() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc new file mode 100644 index 00000000..6df910be --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc @@ -0,0 +1,60 @@ + $obj->{$foo . $bar})()) /* testSwitchArrowFunctionWithinConditionScopeOpener */ { + case 1: + return 'test'; +/* testSwitchArrowFunctionWithinConditionScopeCloser */ +} + +/* testSwitchArrowFunctionWithReturnTypeWithinCondition */ +switch((fn(): string => $condition ? 'foo' : 'bar')()) /* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeOpener */ : + /* testSwitchArrowFunctionWithReturnTypeWithinConditionEnsureTestWillNotPickUpWrongColon */ + case 1: + return 'test'; +/* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeCloser */ +endswitch; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php new file mode 100644 index 00000000..dd6634ac --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php @@ -0,0 +1,160 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapSwitchTokenScopeTest extends AbstractTokenizerTestCase +{ + + + /** + * Tests setting the scope for T_SWITCH token (normal and alternative syntax). + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedTokens The expected token codes for the scope opener/closer. + * @param string|null $testOpenerMarker Optional. The comment which prefaces the scope opener if different + * from the test marker. + * @param string|null $testCloserMarker Optional. The comment which prefaces the scope closer if different + * from the test marker. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/497#ref-commit-b24b96b + * + * @dataProvider dataSwitchScope + * @covers \PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testSwitchScope($testMarker, $expectedTokens, $testOpenerMarker=null, $testCloserMarker=null) + { + $tokens = $this->phpcsFile->getTokens(); + $switchIndex = $this->getTargetToken($testMarker, [T_SWITCH]); + $tokenArray = $tokens[$switchIndex]; + + $scopeOpenerMarker = $testMarker; + if (isset($testOpenerMarker) === true) { + $scopeOpenerMarker = $testOpenerMarker; + } + + $scopeCloserMarker = $testMarker; + if (isset($testCloserMarker) === true) { + $scopeCloserMarker = $testCloserMarker; + } + + $expectedScopeCondition = $switchIndex; + $expectedScopeOpener = $this->getTargetToken($scopeOpenerMarker, $expectedTokens['scope_opener']); + $expectedScopeCloser = $this->getTargetToken($scopeCloserMarker, $expectedTokens['scope_closer']); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_SWITCH, found %s', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testSwitchScope() + + + /** + * Data provider. + * + * @see testSwitchScope() + * + * @return array|null>> + */ + public static function dataSwitchScope() + { + return [ + 'switch normal syntax' => [ + 'testMarker' => '/* testSwitchNormalSyntax */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => null, + 'testCloserMarker' => '/* testSwitchNormalSyntaxScopeCloser */', + ], + 'switch alternative syntax' => [ + 'testMarker' => '/* testSwitchAlternativeSyntax */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testOpenerMarker' => null, + 'testCloserMarker' => '/* testSwitchAlternativeSyntaxScopeCloser */', + ], + 'switch with closure in the condition' => [ + 'testMarker' => '/* testSwitchClosureWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => '/* testSwitchClosureWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchClosureWithinConditionScopeCloser */', + ], + 'switch alternative syntax with closure containing return type in the condition' => [ + 'testMarker' => '/* testSwitchClosureWithReturnTypeWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testOpenerMarker' => '/* testSwitchClosureWithReturnTypeWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchClosureWithReturnTypeWithinConditionScopeCloser */', + ], + 'switch with arrow function in the condition' => [ + 'testMarker' => '/* testSwitchArrowFunctionWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => '/* testSwitchArrowFunctionWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchArrowFunctionWithinConditionScopeCloser */', + ], + 'switch alternative syntax with arrow function containing return type in the condition' => [ + 'testMarker' => '/* testSwitchArrowFunctionWithReturnTypeWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testOpenerMarker' => '/* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeCloser */', + ], + + ]; + + }//end dataSwitchScope() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.inc new file mode 100644 index 00000000..38e5a47d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.inc @@ -0,0 +1,19 @@ + new namespace\Baz; diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.php new file mode 100644 index 00000000..c6acda72 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.php @@ -0,0 +1,98 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapWithNamespaceOperatorTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the scope opener/closers are set correctly when the namespace keyword is encountered as an operator. + * + * @param string $testMarker The comment which prefaces the target tokens in the test file. + * @param array $tokenTypes The token type to search for. + * @param array $open Optional. The token type for the scope opener. + * @param array $close Optional. The token type for the scope closer. + * + * @dataProvider dataScopeSetting + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testScopeSetting($testMarker, $tokenTypes, $open=[T_OPEN_CURLY_BRACKET], $close=[T_CLOSE_CURLY_BRACKET]) + { + $tokens = $this->phpcsFile->getTokens(); + + $target = $this->getTargetToken($testMarker, $tokenTypes); + $opener = $this->getTargetToken($testMarker, $open); + $closer = $this->getTargetToken($testMarker, $close); + + $this->assertArrayHasKey('scope_opener', $tokens[$target], 'Scope opener missing'); + $this->assertArrayHasKey('scope_closer', $tokens[$target], 'Scope closer missing'); + $this->assertSame($opener, $tokens[$target]['scope_opener'], 'Scope opener not same'); + $this->assertSame($closer, $tokens[$target]['scope_closer'], 'Scope closer not same'); + + $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Scope opener missing for open curly'); + $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Scope closer missing for open curly'); + $this->assertSame($opener, $tokens[$opener]['scope_opener'], 'Scope opener not same for open curly'); + $this->assertSame($closer, $tokens[$opener]['scope_closer'], 'Scope closer not same for open curly'); + + $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Scope opener missing for close curly'); + $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Scope closer missing for close curly'); + $this->assertSame($opener, $tokens[$closer]['scope_opener'], 'Scope opener not same for close curly'); + $this->assertSame($closer, $tokens[$closer]['scope_closer'], 'Scope closer not same for close curly'); + + }//end testScopeSetting() + + + /** + * Data provider. + * + * @see testScopeSetting() + * + * @return array>> + */ + public static function dataScopeSetting() + { + return [ + 'class which extends namespace relative name' => [ + 'testMarker' => '/* testClassExtends */', + 'tokenTypes' => [T_CLASS], + ], + 'class which implements namespace relative name' => [ + 'testMarker' => '/* testClassImplements */', + 'tokenTypes' => [T_ANON_CLASS], + ], + 'interface which extend namespace relative name' => [ + 'testMarker' => '/* testInterfaceExtends */', + 'tokenTypes' => [T_INTERFACE], + ], + 'namespace relative name in function return type' => [ + 'testMarker' => '/* testFunctionReturnType */', + 'tokenTypes' => [T_FUNCTION], + ], + 'namespace relative name in closure return type' => [ + 'testMarker' => '/* testClosureReturnType */', + 'tokenTypes' => [T_CLOSURE], + ], + 'namespace relative name in arrow function return type' => [ + 'testMarker' => '/* testArrowFunctionReturnType */', + 'tokenTypes' => [T_FN], + 'open' => [T_FN_ARROW], + 'close' => [T_SEMICOLON], + ], + ]; + + }//end dataScopeSetting() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenMiscTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenMiscTest.php new file mode 100644 index 00000000..f4bd711a --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenMiscTest.php @@ -0,0 +1,124 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Miscellaneous tests for tab replacement. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenMiscTest extends TestCase +{ + + + /** + * Test that when no tab width is set or passed, the tab width will be set to 1. + * + * @return void + */ + public function testTabWidthNotSet() + { + $config = new ConfigDouble(); + $ruleset = new Ruleset($config); + + $content = <<parse(); + + $tokens = $phpcsFile->getTokens(); + $target = $phpcsFile->findNext(T_WHITESPACE, 0); + + // Verify initial state. + $this->assertTrue(is_int($target), 'Target token was not found'); + $this->assertSame(' ', $tokens[$target]['content'], 'Content after initial parsing does not contain tabs'); + $this->assertSame(2, $tokens[$target]['length'], 'Length after initial parsing is not as expected'); + $this->assertArrayNotHasKey('orig_content', $tokens[$target], "Key 'orig_content' found in the initial token array."); + + $phpcsFile->tokenizer->replaceTabsInToken($tokens[$target]); + + // Verify tab replacement. + $this->assertSame(' ', $tokens[$target]['content'], 'Content after tab replacement is not as expected'); + $this->assertSame(2, $tokens[$target]['length'], 'Length after tab replacement is not as expected'); + $this->assertArrayHasKey('orig_content', $tokens[$target], "Key 'orig_content' not found in the token array."); + + }//end testTabWidthNotSet() + + + /** + * Test that the length calculation handles text in non-ascii encodings correctly. + * + * @requires extension iconv + * + * @return void + */ + public function testLengthSettingRespectsEncoding() + { + $config = new ConfigDouble(); + $config->tabWidth = 4; + $ruleset = new Ruleset($config); + + $content = <<parse(); + + $tokens = $phpcsFile->getTokens(); + $target = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, 0); + + $this->assertTrue(is_int($target), 'Target token was not found'); + $this->assertSame("'пасха пасха'", $tokens[$target]['content'], 'Content is not as expected'); + $this->assertSame(17, $tokens[$target]['length'], 'Length is not as expected'); + $this->assertArrayHasKey('orig_content', $tokens[$target], "Key 'orig_content' not found in the token array."); + $this->assertSame("'пасха пасха'", $tokens[$target]['orig_content'], 'Orig_content is not as expected'); + + }//end testLengthSettingRespectsEncoding() + + + /** + * Test that the length calculation falls back to byte length if iconv detects an illegal character. + * + * @requires extension iconv + * + * @return void + */ + public function testLengthSettingFallsBackToBytesWhenTextContainsIllegalChars() + { + $config = new ConfigDouble(); + $config->tabWidth = 4; + $ruleset = new Ruleset($config); + + $content = <<parse(); + + $tokens = $phpcsFile->getTokens(); + $target = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, 0); + + $this->assertTrue(is_int($target), 'Target token was not found'); + $this->assertSame(11, $tokens[$target]['length'], 'Length is not as expected'); + $this->assertArrayHasKey('orig_content', $tokens[$target], "Key 'orig_content' not found in the token array."); + + }//end testLengthSettingFallsBackToBytesWhenTextContainsIllegalChars() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth1Test.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth1Test.php new file mode 100644 index 00000000..29621534 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth1Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 1. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth1Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 1; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 2, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 3, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 24, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 15, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 27, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 20, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 31, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 52, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 45, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth2Test.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth2Test.php new file mode 100644 index 00000000..92de221d --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth2Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 2. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth2Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 2; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 4, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 4, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 26, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 17, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 34, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 23, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 32, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 53, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 45, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 48, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth4Test.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth4Test.php new file mode 100644 index 00000000..5f741879 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth4Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 4. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth4Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 4; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 8, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 6, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 17, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 32, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 21, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 48, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 25, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 36, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 53, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth5Test.php b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth5Test.php new file mode 100644 index 00000000..361894fb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth5Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 5. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth5Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 5; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 10, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 7, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 25, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 24, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 54, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 30, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 35, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 52, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 55, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 49, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTest.inc b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTest.inc new file mode 100644 index 00000000..e6046500 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTest.inc @@ -0,0 +1,46 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use Exception; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tab replacement test case. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +abstract class ReplaceTabsInTokenTestCase extends AbstractTokenizerTestCase +{ + + /** + * The name of the test case file used by this test. + * + * @var string + */ + private static $caseFileName; + + + /** + * Make a copy the test case file we want to use for this test (as the file will be used by multiple tests). + * + * @beforeClass + * + * @return void + * + * @throws \Exception In case the base test case file would not be available. + */ + public static function copyCaseFile() + { + $relativeCN = str_replace(__NAMESPACE__.'\\', '', get_called_class()); + self::$caseFileName = __DIR__.DIRECTORY_SEPARATOR.$relativeCN.'.inc'; + + $baseFileName = realpath(__DIR__.'/ReplaceTabsInTokenTest.inc'); + if (is_string($baseFileName) === false) { + throw new Exception('Base test case file "ReplaceTabsInTokenTest.inc" not found'); + } + + if (copy($baseFileName, self::$caseFileName) === false) { + throw new Exception(sprintf('Failed to copy test case file "ReplaceTabsInTokenTest.inc" to %s', self::$caseFileName)); + } + + }//end copyCaseFile() + + + /** + * Delete the copied test case file after use. + * + * @afterClass + * + * @return void + */ + public static function deleteCaseFile() + { + @unlink(self::$caseFileName); + + }//end deleteCaseFile() + + + /** + * Verify that if a token not containing tabs would be passed to the replaceTabsInToken() method, + * yes, the `orig_content` key is added, but no changes are made to the token `content` or `length` values. + * + * @param string $testMarker The comment prefacing the target token. + * @param int|string $testTarget Token code to look for. + * @param array $expected Expectations for the token array. + * @param int $offset Optional. Offset from the target token to get to the _real_ target. + * This is specifically needed to target indentation whitespace. + * + * @dataProvider dataNoReplacementsAreMadeWhenNoTabsAreFound + * + * @return void + */ + public function testNoReplacementsAreMadeWhenNoTabsAreFound($testMarker, $testTarget, $expected, $offset=0) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, $testTarget); + $target += $offset; + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation."); + } + + }//end testNoReplacementsAreMadeWhenNoTabsAreFound() + + + /** + * Data provider. + * + * @see testNoReplacementsAreMadeWhenNoTabsAreFound() + * + * @return array>> + */ + public static function dataNoReplacementsAreMadeWhenNoTabsAreFound() + { + return [ + 'Indentation whitespace, only spaces' => [ + 'testMarker' => '/* testNoReplacementNeeded */', + 'testTarget' => T_WHITESPACE, + 'expected' => [ + 'length' => 4, + 'content' => ' ', + 'orig_content' => null, + ], + 'offset' => 1, + ], + 'Trailing comment not containing any tabs' => [ + 'testMarker' => '/* testNoReplacementNeeded */', + 'testTarget' => T_COMMENT, + 'expected' => [ + 'length' => 35, + 'content' => '// Comment not containing any tabs. +', + 'orig_content' => null, + ], + ], + ]; + + }//end dataNoReplacementsAreMadeWhenNoTabsAreFound() + + + /** + * Test tab replacement in tokens. + * + * @param string $testMarker The comment prefacing the target token. + * @param int|string $testTarget Token code to look for. + * @param array $expected Expectations for the token array. + * @param int $offset Optional. Offset from the target token to get to the _real_ target. + * This is specifically needed to target indentation whitespace. + * + * @dataProvider dataTabReplacement + * + * @return void + */ + public function testTabReplacement($testMarker, $testTarget, $expected, $offset=0) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, $testTarget); + $target += $offset; + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation."); + } + + }//end testTabReplacement() + + + /** + * Data provider. + * + * @see testTabReplacement() + * + * @return array>> + * + * @throws \Exception When the getTabReplacementExpected() method doesn't provide data in the correct format. + */ + public static function dataTabReplacement() + { + $data = [ + 'Tab indentation' => [ + 'testMarker' => '/* testTabIndentation */', + 'testTarget' => T_WHITESPACE, + ], + 'Mixed tab/space indentation' => [ + 'testMarker' => '/* testMixedIndentation */', + 'testTarget' => T_WHITESPACE, + ], + 'Inline: single tab in text string' => [ + 'testMarker' => '/* testInlineSingleTab */', + 'testTarget' => T_CONSTANT_ENCAPSED_STRING, + ], + 'Inline: single tab between each word in text string' => [ + 'testMarker' => '/* testInlineSingleTabBetweenEachWord */', + 'testTarget' => T_DOUBLE_QUOTED_STRING, + ], + 'Inline: multiple tabs in heredoc' => [ + 'testMarker' => '/* testInlineMultiTab */', + 'testTarget' => T_HEREDOC, + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'testMarker' => '/* testInlineMultipleTabsBetweenEachWord */', + 'testTarget' => T_NOWDOC, + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'testMarker' => '/* testInlineMixedSpacesTabs */', + 'testTarget' => T_CONSTANT_ENCAPSED_STRING, + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'testMarker' => '/* testInlineMixedSpacesTabsBetweenEachWord */', + 'testTarget' => T_DOUBLE_QUOTED_STRING, + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize1 */', + 'testTarget' => T_COMMENT, + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize2 */', + 'testTarget' => T_COMMENT, + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize3 */', + 'testTarget' => T_DOC_COMMENT_STRING, + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize4 */', + 'testTarget' => T_COMMENT, + ], + ]; + + $expectations = static::getTabReplacementExpected(); + + foreach ($data as $key => $value) { + if (isset($expectations[$key]) === false || is_array($expectations[$key]) === false) { + throw new Exception( + sprintf('Invalid getTabReplacementExpected() method. Missing expectation array for the "%s" test case', $key) + ); + } + + if (isset($expectations[$key]['length'], $expectations[$key]['content']) === false + || array_key_exists('orig_content', $expectations[$key]) === false + ) { + throw new Exception( + sprintf('Invalid expectation array for the "%s" test case. The array must contain the "length", "content" and "orig_content" keys', $key) + ); + } + + $data[$key]['expected'] = $expectations[$key]; + } + + // Set offset for test cases targetting whitespace. + $data['Tab indentation']['offset'] = 1; + $data['Mixed tab/space indentation']['offset'] = 1; + + return $data; + + }//end dataTabReplacement() + + + /** + * Data provider helper. + * + * Should be declared in child classes to set the expectations for the token array. + * + * @see dataTabReplacement() + * + * @return array> + */ + abstract public static function getTabReplacementExpected(); + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/EscapeshellcmdTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/EscapeshellcmdTest.php new file mode 100644 index 00000000..2844c4a3 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/EscapeshellcmdTest.php @@ -0,0 +1,91 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::escapeshellcmd() method. + * + * @covers \PHP_CodeSniffer\Util\Common::escapeshellcmd + * @group Windows + */ +final class EscapeshellcmdTest extends TestCase +{ + + + /** + * Test escaping shell commands. + * + * @param string $command The command provided. + * @param string $expected Expected function output. + * @param string $expectedWin Optional. Expected function output on Windows. + * Only needs to be passed if the output on Windows would be different. + * + * @dataProvider dataEscapeshellcmd + * + * @return void + */ + public function testEscapeshellcmd($command, $expected, $expectedWin=null) + { + if (stripos(PHP_OS, 'WIN') === 0 && empty($expectedWin) === false) { + $expected = $expectedWin; + } + + $this->assertSame($expected, Common::escapeshellcmd($command)); + + }//end testEscapeshellcmd() + + + /** + * Data provider. + * + * Note: we're only testing the PHPCS functionality, not the PHP native `escapeshellcmd()` + * function (as that's not our responsibility). + * + * @see testEscapeshellcmd() + * + * @return array> + */ + public static function dataEscapeshellcmd() + { + return [ + 'Command is empty string' => [ + 'command' => '', + 'expected' => '', + ], + 'Command is simple string' => [ + 'command' => 'csslint', + 'expected' => 'csslint', + ], + 'Command containing characters which PHP escapes' => [ + 'command' => '&#;`|*?~<>^()[]{}$\,%!', + 'expected' => '\&\#\;\`\|\*\?\~\<\>\^\(\)\[\]\{\}\$\\\\,%!', + 'expectedWin' => '^&^#^;^`^|^*^?^~^<^>^^^(^)^[^]^{^}^$^\,^%^!', + ], + // @link https://github.com/squizlabs/PHP_CodeSniffer/pull/3214 + 'Command containing spaces, which can cause problems on Windows' => [ + 'command' => 'C:\Program Files\nodejs\csslint.cmd', + 'expected' => 'C:\\\\Program Files\\\\nodejs\\\\csslint.cmd', + 'expectedWin' => 'C:^\Program^ Files^\nodejs^\csslint.cmd', + ], + // @link https://github.com/php/doc-en/pull/511 + 'Command containing spaces with additional arguments' => [ + 'command' => 'php -f ./~home/path to/file.php', + 'expected' => 'php -f ./\~home/path to/file.php', + 'expectedWin' => 'php^ -f^ ./^~home/path^ to/file.php', + ], + ]; + + }//end dataEscapeshellcmd() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/GetSniffCodeTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/GetSniffCodeTest.php new file mode 100644 index 00000000..444ea5eb --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/GetSniffCodeTest.php @@ -0,0 +1,212 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::getSniffCode() method. + * + * @covers \PHP_CodeSniffer\Util\Common::getSniffCode + */ +final class GetSniffCodeTest extends TestCase +{ + + + /** + * Test receiving an expected exception when the $sniffClass parameter is not passed a string value or is passed an empty string. + * + * @param mixed $input NOT a fully qualified sniff class name. + * + * @dataProvider dataGetSniffCodeThrowsExceptionOnInvalidInput + * + * @return void + */ + public function testGetSniffCodeThrowsExceptionOnInvalidInput($input) + { + $exception = 'InvalidArgumentException'; + $message = 'The $sniffClass parameter must be a non-empty string'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + Common::getSniffCode($input); + + }//end testGetSniffCodeThrowsExceptionOnInvalidInput() + + + /** + * Data provider. + * + * @see testGetSniffCodeThrowsExceptionOnInvalidInput() + * + * @return array> + */ + public static function dataGetSniffCodeThrowsExceptionOnInvalidInput() + { + return [ + 'Class name is not a string' => [true], + 'Class name is empty' => [''], + ]; + + }//end dataGetSniffCodeThrowsExceptionOnInvalidInput() + + + /** + * Test receiving an expected exception when the $sniffClass parameter is not passed a value which + * could be a fully qualified sniff(test) class name. + * + * @param string $input String input which can not be a fully qualified sniff(test) class name. + * + * @dataProvider dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass + * + * @return void + */ + public function testGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass($input) + { + $exception = 'InvalidArgumentException'; + $message = 'The $sniffClass parameter was not passed a fully qualified sniff(test) class name. Received:'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + Common::getSniffCode($input); + + }//end testGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + + + /** + * Data provider. + * + * @see testGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + * + * @return array> + */ + public static function dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + { + return [ + 'Unqualified class name' => ['ClassName'], + 'Fully qualified class name, not enough parts' => ['Fully\\Qualified\\ClassName'], + 'Fully qualified class name, doesn\'t end on Sniff or UnitTest' => ['Fully\\Sniffs\\Qualified\\ClassName'], + ]; + + }//end dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + + + /** + * Test transforming a sniff class name to a sniff code. + * + * @param string $fqnClass A fully qualified sniff class name. + * @param string $expected Expected function output. + * + * @dataProvider dataGetSniffCode + * + * @return void + */ + public function testGetSniffCode($fqnClass, $expected) + { + $this->assertSame($expected, Common::getSniffCode($fqnClass)); + + }//end testGetSniffCode() + + + /** + * Data provider. + * + * @see testGetSniffCode() + * + * @return array> + */ + public static function dataGetSniffCode() + { + return [ + 'PHPCS native sniff' => [ + 'fqnClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Arrays\\ArrayIndentSniff', + 'expected' => 'Generic.Arrays.ArrayIndent', + ], + 'Class is a PHPCS native test class' => [ + 'fqnClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Tests\\Arrays\\ArrayIndentUnitTest', + 'expected' => 'Generic.Arrays.ArrayIndent', + ], + 'Sniff in external standard without namespace prefix' => [ + 'fqnClass' => 'MyStandard\\Sniffs\\PHP\\MyNameSniff', + 'expected' => 'MyStandard.PHP.MyName', + ], + 'Test in external standard without namespace prefix' => [ + 'fqnClass' => 'MyStandard\\Tests\\PHP\\MyNameUnitTest', + 'expected' => 'MyStandard.PHP.MyName', + ], + 'Sniff in external standard with namespace prefix' => [ + 'fqnClass' => 'Vendor\\Package\\MyStandard\\Sniffs\\Category\\AnalyzeMeSniff', + 'expected' => 'MyStandard.Category.AnalyzeMe', + ], + 'Test in external standard with namespace prefix' => [ + 'fqnClass' => 'Vendor\\Package\\MyStandard\\Tests\\Category\\AnalyzeMeUnitTest', + 'expected' => 'MyStandard.Category.AnalyzeMe', + ], + + /* + * These are not valid sniff codes and is an undesirable result, but can't be helped + * as changing this would be a BC-break. + * Supporting these to allow for tags directly including sniff files. + * See: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/675 + */ + + 'Fully qualified class name, ends on Sniff, but isn\'t' => [ + 'fqnClass' => 'Fully\\Sniffs\\AbstractSomethingSniff', + 'expected' => '.Sniffs.AbstractSomething', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [1]' => [ + 'fqnClass' => 'CheckMeSniff', + 'expected' => '..CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [2]' => [ + 'fqnClass' => 'CompanyName\\CheckMeSniff', + 'expected' => '.CompanyName.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [3]' => [ + 'fqnClass' => 'CompanyName\\Sniffs\\CheckMeSniff', + 'expected' => '.Sniffs.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [4]' => [ + 'fqnClass' => 'CompanyName\\CustomSniffs\\Whatever\\CheckMeSniff', + 'expected' => 'CompanyName.Whatever.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [5]' => [ + 'fqnClass' => 'CompanyName\\Sniffs\\Category\\Sniff', + 'expected' => 'CompanyName.Category.', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [6]' => [ + 'fqnClass' => 'CompanyName\\Tests\\Category\\UnitTest', + 'expected' => 'CompanyName.Category.', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [7]' => [ + 'fqnClass' => 'Sniffs\\Category\\NamedSniff', + 'expected' => '.Category.Named', + ], + ]; + + }//end dataGetSniffCode() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/IsCamelCapsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/IsCamelCapsTest.php new file mode 100644 index 00000000..951d7618 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/IsCamelCapsTest.php @@ -0,0 +1,140 @@ + + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::isCamelCaps method. + * + * @covers \PHP_CodeSniffer\Util\Common::isCamelCaps + */ +final class IsCamelCapsTest extends TestCase +{ + + + /** + * Test valid public function/method names. + * + * @return void + */ + public function testValidNotClassFormatPublic() + { + $this->assertTrue(Common::isCamelCaps('thisIsCamelCaps', false, true, true)); + $this->assertTrue(Common::isCamelCaps('thisISCamelCaps', false, true, false)); + + }//end testValidNotClassFormatPublic() + + + /** + * Test invalid public function/method names. + * + * @return void + */ + public function testInvalidNotClassFormatPublic() + { + $this->assertFalse(Common::isCamelCaps('_thisIsCamelCaps', false, true, true)); + $this->assertFalse(Common::isCamelCaps('thisISCamelCaps', false, true, true)); + $this->assertFalse(Common::isCamelCaps('ThisIsCamelCaps', false, true, true)); + + $this->assertFalse(Common::isCamelCaps('3thisIsCamelCaps', false, true, true)); + $this->assertFalse(Common::isCamelCaps('*thisIsCamelCaps', false, true, true)); + $this->assertFalse(Common::isCamelCaps('-thisIsCamelCaps', false, true, true)); + + $this->assertFalse(Common::isCamelCaps('this*IsCamelCaps', false, true, true)); + $this->assertFalse(Common::isCamelCaps('this-IsCamelCaps', false, true, true)); + $this->assertFalse(Common::isCamelCaps('this_IsCamelCaps', false, true, true)); + $this->assertFalse(Common::isCamelCaps('this_is_camel_caps', false, true, true)); + + }//end testInvalidNotClassFormatPublic() + + + /** + * Test valid private method names. + * + * @return void + */ + public function testValidNotClassFormatPrivate() + { + $this->assertTrue(Common::isCamelCaps('_thisIsCamelCaps', false, false, true)); + $this->assertTrue(Common::isCamelCaps('_thisISCamelCaps', false, false, false)); + $this->assertTrue(Common::isCamelCaps('_i18N', false, false, true)); + $this->assertTrue(Common::isCamelCaps('_i18n', false, false, true)); + + }//end testValidNotClassFormatPrivate() + + + /** + * Test invalid private method names. + * + * @return void + */ + public function testInvalidNotClassFormatPrivate() + { + $this->assertFalse(Common::isCamelCaps('thisIsCamelCaps', false, false, true)); + $this->assertFalse(Common::isCamelCaps('_thisISCamelCaps', false, false, true)); + $this->assertFalse(Common::isCamelCaps('_ThisIsCamelCaps', false, false, true)); + $this->assertFalse(Common::isCamelCaps('__thisIsCamelCaps', false, false, true)); + $this->assertFalse(Common::isCamelCaps('__thisISCamelCaps', false, false, false)); + + $this->assertFalse(Common::isCamelCaps('3thisIsCamelCaps', false, false, true)); + $this->assertFalse(Common::isCamelCaps('*thisIsCamelCaps', false, false, true)); + $this->assertFalse(Common::isCamelCaps('-thisIsCamelCaps', false, false, true)); + $this->assertFalse(Common::isCamelCaps('_this_is_camel_caps', false, false, true)); + + }//end testInvalidNotClassFormatPrivate() + + + /** + * Test valid class names. + * + * @return void + */ + public function testValidClassFormatPublic() + { + $this->assertTrue(Common::isCamelCaps('ThisIsCamelCaps', true, true, true)); + $this->assertTrue(Common::isCamelCaps('ThisISCamelCaps', true, true, false)); + $this->assertTrue(Common::isCamelCaps('This3IsCamelCaps', true, true, false)); + + }//end testValidClassFormatPublic() + + + /** + * Test invalid class names. + * + * @return void + */ + public function testInvalidClassFormat() + { + $this->assertFalse(Common::isCamelCaps('thisIsCamelCaps', true)); + $this->assertFalse(Common::isCamelCaps('This-IsCamelCaps', true)); + $this->assertFalse(Common::isCamelCaps('This_Is_Camel_Caps', true)); + + }//end testInvalidClassFormat() + + + /** + * Test invalid class names with the private flag set. + * + * Note that the private flag is ignored if the class format + * flag is set, so these names are all invalid. + * + * @return void + */ + public function testInvalidClassFormatPrivate() + { + $this->assertFalse(Common::isCamelCaps('_ThisIsCamelCaps', true, true)); + $this->assertFalse(Common::isCamelCaps('_ThisIsCamelCaps', true, false)); + + }//end testInvalidClassFormatPrivate() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/PrepareForOutputTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/PrepareForOutputTest.php new file mode 100644 index 00000000..8eb2fc22 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/PrepareForOutputTest.php @@ -0,0 +1,113 @@ +assertSame($expected, Common::prepareForOutput($content, $exclude)); + + }//end testPrepareForOutput() + + + /** + * Test formatting whitespace characters, on Windows. + * + * @param string $content The content to prepare. + * @param string[] $exclude A list of characters to leave invisible. + * @param string $expected Expected function output (unused in this test). + * @param string $expectedWin Expected function output on Windows. + * + * @requires OS ^WIN.*. + * @dataProvider dataPrepareForOutput + * + * @return void + */ + public function testPrepareForOutputWindows($content, $exclude, $expected, $expectedWin) + { + $this->assertSame($expectedWin, Common::prepareForOutput($content, $exclude)); + + }//end testPrepareForOutputWindows() + + + /** + * Data provider. + * + * @see testPrepareForOutput() + * @see testPrepareForOutputWindows() + * + * @return array> + */ + public static function dataPrepareForOutput() + { + return [ + 'Special characters are replaced with their escapes' => [ + 'content' => "\r\n\t", + 'exclude' => [], + 'expected' => "\033[30;1m\\r\033[0m\033[30;1m\\n\033[0m\033[30;1m\\t\033[0m", + 'expectedWin' => "\\r\\n\\t", + ], + 'Spaces are replaced with a unique mark' => [ + 'content' => " ", + 'exclude' => [], + 'expected' => "\033[30;1m·\033[0m\033[30;1m·\033[0m\033[30;1m·\033[0m\033[30;1m·\033[0m", + 'expectedWin' => " ", + ], + 'Other characters are unaffected' => [ + 'content' => "{echo 1;}", + 'exclude' => [], + 'expected' => "{echo\033[30;1m·\033[0m1;}", + 'expectedWin' => "{echo 1;}", + ], + 'No replacements' => [ + 'content' => 'nothing-should-be-replaced', + 'exclude' => [], + 'expected' => 'nothing-should-be-replaced', + 'expectedWin' => 'nothing-should-be-replaced', + ], + 'Excluded whitespace characters are unaffected' => [ + 'content' => "\r\n\t ", + 'exclude' => [ + "\r", + "\n", + ], + 'expected' => "\r\n\033[30;1m\\t\033[0m\033[30;1m·\033[0m", + 'expectedWin' => "\r\n\\t ", + ], + ]; + + }//end dataPrepareForOutput() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/StripColorsTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/StripColorsTest.php new file mode 100644 index 00000000..ff253b8b --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/StripColorsTest.php @@ -0,0 +1,96 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::stripColors() method. + * + * @covers \PHP_CodeSniffer\Util\Common::stripColors + */ +final class StripColorsTest extends TestCase +{ + + + /** + * Test stripping color codes from a text. + * + * @param string $text The text provided. + * @param string $expected Expected function output. + * + * @dataProvider dataStripColors + * + * @return void + */ + public function testStripColors($text, $expected) + { + $this->assertSame($expected, Common::stripColors($text)); + + }//end testStripColors() + + + /** + * Data provider. + * + * @see testStripColors() + * + * @return array> + */ + public static function dataStripColors() + { + return [ + 'Text is empty' => [ + 'text' => '', + 'expected' => '', + ], + 'Text enclosed in color code' => [ + 'text' => "\033[36mSome text\033[0m", + 'expected' => 'Some text', + ], + 'Text containing color code' => [ + 'text' => "Some text \033[33mSome other text", + 'expected' => 'Some text Some other text', + ], + 'Text enclosed in color code, bold' => [ + 'text' => "\033[1;32mSome text\033[0m", + 'expected' => 'Some text', + ], + 'Text enclosed in color code, with escaped text' => [ + 'text' => "\033[30;1m\\n\033[0m", + 'expected' => '\n', + ], + 'Text enclosed in color code, bold, dark, italic' => [ + 'text' => "\033[1;2;3mtext\033[0m", + 'expected' => 'text', + ], + 'Text enclosed in color code, foreground color' => [ + 'text' => "\033[38;5;255mtext\033[0m", + 'expected' => 'text', + ], + 'Text enclosed in color code, foreground color and background color' => [ + 'text' => "\033[38;5;200;48;5;255mtext\033[0m", + 'expected' => 'text', + ], + 'Multiline text containing multiple color codes' => [ + 'text' => "First \033[36mSecond\033[0m +Third \033[1;2;3mFourth +Next line\033[0m Last", + 'expected' => 'First Second +Third Fourth +Next line Last', + ], + ]; + + }//end dataStripColors() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/SuggestTypeTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/SuggestTypeTest.php new file mode 100644 index 00000000..48bb6df1 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/SuggestTypeTest.php @@ -0,0 +1,224 @@ + + * @copyright 2019 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::suggestType() method. + * + * @covers \PHP_CodeSniffer\Util\Common::suggestType + */ +final class SuggestTypeTest extends TestCase +{ + + + /** + * Test passing an empty type to the suggestType() method. + * + * @return void + */ + public function testSuggestTypeEmpty() + { + $this->assertSame('', Common::suggestType('')); + + }//end testSuggestTypeEmpty() + + + /** + * Test passing one of the allowed types to the suggestType() method. + * + * @param string $varType The type. + * + * @dataProvider dataSuggestTypeAllowedType + * + * @return void + */ + public function testSuggestTypeAllowedType($varType) + { + $result = Common::suggestType($varType); + $this->assertSame($varType, $result); + + }//end testSuggestTypeAllowedType() + + + /** + * Data provider. + * + * @see testSuggestTypeAllowedType() + * + * @return array> + */ + public static function dataSuggestTypeAllowedType() + { + $data = []; + foreach (Common::$allowedTypes as $type) { + $data['Type: '.$type] = [$type]; + } + + return $data; + + }//end dataSuggestTypeAllowedType() + + + /** + * Test passing one of the allowed types in the wrong case to the suggestType() method. + * + * @param string $varType The type found. + * @param string $expected Expected suggested type. + * + * @dataProvider dataSuggestTypeAllowedTypeWrongCase + * + * @return void + */ + public function testSuggestTypeAllowedTypeWrongCase($varType, $expected) + { + $result = Common::suggestType($varType); + $this->assertSame($expected, $result); + + }//end testSuggestTypeAllowedTypeWrongCase() + + + /** + * Data provider. + * + * @see testSuggestTypeAllowedTypeWrongCase() + * + * @return array> + */ + public static function dataSuggestTypeAllowedTypeWrongCase() + { + $data = []; + foreach (Common::$allowedTypes as $type) { + $data['Mixed case: '.$type] = [ + 'varType' => ucfirst($type), + 'expected' => $type, + ]; + $data['Uppercase: '.$type] = [ + 'varType' => strtoupper($type), + 'expected' => $type, + ]; + } + + return $data; + + }//end dataSuggestTypeAllowedTypeWrongCase() + + + /** + * Test the suggestType() method for all other cases. + * + * @param string $varType The type found. + * @param string $expected Expected suggested type. + * + * @dataProvider dataSuggestTypeOther + * + * @return void + */ + public function testSuggestTypeOther($varType, $expected) + { + $result = Common::suggestType($varType); + $this->assertSame($expected, $result); + + }//end testSuggestTypeOther() + + + /** + * Data provider. + * + * @see testSuggestTypeOther() + * + * @return array> + */ + public static function dataSuggestTypeOther() + { + return [ + // Short forms. + 'Short form type: bool, lowercase' => [ + 'varType' => 'bool', + 'expected' => 'boolean', + ], + 'Short form type: bool, uppercase' => [ + 'varType' => 'BOOL', + 'expected' => 'boolean', + ], + 'Short form type: double, lowercase' => [ + 'varType' => 'double', + 'expected' => 'float', + ], + 'Short form type: real, mixed case' => [ + 'varType' => 'Real', + 'expected' => 'float', + ], + 'Short form type: double, mixed case' => [ + 'varType' => 'DoUbLe', + 'expected' => 'float', + ], + 'Short form type: int, lowercase' => [ + 'varType' => 'int', + 'expected' => 'integer', + ], + 'Short form type: int, uppercase' => [ + 'varType' => 'INT', + 'expected' => 'integer', + ], + + // Array types. + 'Array type: mixed case keyword, empty parentheses' => [ + 'varType' => 'Array()', + 'expected' => 'array', + ], + 'Array type: short form type as value within the parentheses' => [ + 'varType' => 'array(real)', + 'expected' => 'array(float)', + ], + 'Array type: short form type as key within the parentheses' => [ + 'varType' => 'array(int => object)', + 'expected' => 'array(integer => object)', + ], + 'Array type: valid specification' => [ + 'varType' => 'array(integer => array(string => resource))', + 'expected' => 'array(integer => array(string => resource))', + ], + 'Array type: short form + uppercase types within the parentheses' => [ + 'varType' => 'ARRAY(BOOL => DOUBLE)', + 'expected' => 'array(boolean => float)', + ], + 'Array type: no space around the arrow within the parentheses' => [ + 'varType' => 'array(string=>resource)', + 'expected' => 'array(string => resource)', + ], + + // Incomplete array type. + 'Array type: incomplete specification' => [ + 'varType' => 'array(int =>', + 'expected' => 'array', + ], + + // Custom types are returned unchanged. + 'Unknown type: " => "' => [ + 'varType' => ' => ', + 'expected' => ' => ', + ], + 'Unknown type: "string[]"' => [ + 'varType' => 'string[]', + 'expected' => 'string[]', + ], + 'Unknown type: "\DateTime"' => [ + 'varType' => '\DateTime', + 'expected' => '\DateTime', + ], + ]; + + }//end dataSuggestTypeOther() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Help/HelpTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Help/HelpTest.php new file mode 100644 index 00000000..b3d51a5c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Help/HelpTest.php @@ -0,0 +1,769 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Help; + +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Util\Help; +use PHPUnit\Framework\TestCase; +use ReflectionMethod; +use ReflectionProperty; + +/** + * Test the Help class. + * + * @covers \PHP_CodeSniffer\Util\Help + */ +final class HelpTest extends TestCase +{ + + + /** + * QA check: verify that the category names are at most the minimum screen width + * and that option argument names are always at most half the length of the minimum screen width. + * + * If this test would start failing, either wrapping of argument info would need to be implemented + * or the minimum screen width needs to be upped. + * + * @coversNothing + * + * @return void + */ + public function testQaArgumentNamesAreWithinAcceptableBounds() + { + $help = new Help(new ConfigDouble(), []); + + $reflMethod = new ReflectionMethod($help, 'getAllOptions'); + $reflMethod->setAccessible(true); + $allOptions = $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $this->assertGreaterThan(0, count($allOptions), 'No categories found'); + + $minScreenWidth = Help::MIN_WIDTH; + $maxArgWidth = ($minScreenWidth / 2); + + foreach ($allOptions as $category => $options) { + $this->assertLessThanOrEqual( + Help::MIN_WIDTH, + strlen($category), + "Category name $category is longer than the minimum screen width of $minScreenWidth" + ); + + foreach ($options as $option) { + if (isset($option['argument']) === false) { + continue; + } + + $this->assertLessThanOrEqual( + $maxArgWidth, + strlen($option['argument']), + "Option name {$option['argument']} is longer than the half the minimum screen width of $minScreenWidth" + ); + } + } + + }//end testQaArgumentNamesAreWithinAcceptableBounds() + + + /** + * QA check: verify that each option only contains a spacer, text or argument + description combo. + * + * @coversNothing + * + * @return void + */ + public function testQaValidCategoryOptionDefinitions() + { + $help = new Help(new ConfigDouble(), []); + + $reflMethod = new ReflectionMethod($help, 'getAllOptions'); + $reflMethod->setAccessible(true); + $allOptions = $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $this->assertGreaterThan(0, count($allOptions), 'No categories found'); + + foreach ($allOptions as $category => $options) { + $this->assertGreaterThan(0, count($options), "No options found in category $category"); + + foreach ($options as $name => $option) { + if (isset($option['spacer']) === true) { + $this->assertStringStartsWith('blank-line', $name, 'The name for spacer items should start with "blank-line"'); + } + + $this->assertFalse( + isset($option['spacer'], $option['text']), + "Option $name: spacer and text should not be combined in one option" + ); + $this->assertFalse( + isset($option['spacer'], $option['argument']), + "Option $name: spacer and argument should not be combined in one option" + ); + $this->assertFalse( + isset($option['spacer'], $option['description']), + "Option $name: spacer and description should not be combined in one option" + ); + $this->assertFalse( + isset($option['text'], $option['argument']), + "Option $name: text and argument should not be combined in one option" + ); + $this->assertFalse( + isset($option['text'], $option['description']), + "Option $name: text and description should not be combined in one option" + ); + + if (isset($option['argument']) === true) { + $this->assertArrayHasKey( + 'description', + $option, + "Option $name: an argument should always be accompanied by a description" + ); + } + + if (isset($option['description']) === true) { + $this->assertArrayHasKey( + 'argument', + $option, + "Option $name: a description should always be accompanied by an argument" + ); + } + }//end foreach + }//end foreach + + }//end testQaValidCategoryOptionDefinitions() + + + /** + * Test receiving an expected exception when the shortOptions parameter is not passed a string value. + * + * @return void + */ + public function testConstructorInvalidArgumentException() + { + $exception = 'InvalidArgumentException'; + $message = 'The $shortOptions parameter must be a string'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + new Help(new ConfigDouble(), [], []); + + }//end testConstructorInvalidArgumentException() + + + /** + * Test filtering of the options by requested options. + * + * Tests that: + * - Options not explicitly requested are removed. + * - Short options passed via the longOptions array are still respected. + * - A category gets removed if all options are removed, even if the category still has spacers. + * + * @param array $longOptions The long options which should be displayed. + * @param string $shortOptions The short options which should be displayed. + * @param array $expected The categories expected after filtering with the number + * of expected help items per category. + * + * @dataProvider dataOptionFiltering + * + * @return void + */ + public function testOptionFiltering($longOptions, $shortOptions, $expected) + { + $help = new Help(new ConfigDouble(), $longOptions, $shortOptions); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $activeOptions = $reflProperty->getValue($help); + $reflProperty->setAccessible(false); + + // Simplify the value to make it comparible. + foreach ($activeOptions as $category => $options) { + $activeOptions[$category] = count($options); + } + + $this->assertSame($expected, $activeOptions, 'Option count per category does not match'); + + }//end testOptionFiltering() + + + /** + * Data provider. + * + * @return array|array>> + */ + public static function dataOptionFiltering() + { + $allLongOptions = explode(',', Help::DEFAULT_LONG_OPTIONS); + $allLongOptions[] = 'cache'; + $allLongOptions[] = 'no-cache'; + $allLongOptions[] = 'report'; + $allLongOptions[] = 'report-file'; + $allLongOptions[] = 'report-report'; + $allLongOptions[] = 'runtime-set'; + $allLongOptions[] = 'config-explain'; + $allLongOptions[] = 'config-set'; + $allLongOptions[] = 'config-delete'; + $allLongOptions[] = 'config-show'; + $allLongOptions[] = 'generator'; + $allLongOptions[] = 'suffix'; + + $allShortOptions = Help::DEFAULT_SHORT_OPTIONS.'saem'; + + return [ + 'No options' => [ + 'longOptions' => [], + 'shortOptions' => '', + 'expected' => [], + ], + 'Invalid options have no influence' => [ + 'longOptions' => [ + 'doesnotexist', + 'invalid', + ], + 'shortOptions' => 'bjrz', + 'expected' => [], + ], + 'Short options passed as long options works fine' => [ + 'longOptions' => [ + 's', + 'suffix', + 'a', + 'e', + 'colors', + ], + 'shortOptions' => '', + 'expected' => [ + 'Rule Selection Options' => 1, + 'Run Options' => 2, + 'Reporting Options' => 2, + ], + ], + 'All options' => [ + 'longOptions' => $allLongOptions, + 'shortOptions' => $allShortOptions, + 'expected' => [ + 'Scan targets' => 8, + 'Rule Selection Options' => 7, + 'Run Options' => 8, + 'Reporting Options' => 19, + 'Configuration Options' => 8, + 'Miscellaneous Options' => 5, + ], + ], + 'Default options only' => [ + 'longOptions' => explode(',', Help::DEFAULT_LONG_OPTIONS), + 'shortOptions' => Help::DEFAULT_SHORT_OPTIONS, + 'expected' => [ + 'Scan targets' => 8, + 'Rule Selection Options' => 5, + 'Run Options' => 4, + 'Reporting Options' => 14, + 'Configuration Options' => 4, + 'Miscellaneous Options' => 5, + ], + ], + 'Only one category' => [ + 'longOptions' => [ + 'file', + 'stdin-path', + 'file-list', + 'filter', + 'ignore', + 'extensions', + ], + 'shortOptions' => '-l', + 'expected' => [ + 'Scan targets' => 8, + ], + ], + 'All except one category' => [ + 'longOptions' => array_diff($allLongOptions, ['version', 'vv', 'vvv']), + 'shortOptions' => str_replace(['h', 'v'], '', $allShortOptions), + 'expected' => [ + 'Scan targets' => 8, + 'Rule Selection Options' => 7, + 'Run Options' => 8, + 'Reporting Options' => 19, + 'Configuration Options' => 8, + ], + ], + ]; + + }//end dataOptionFiltering() + + + /** + * Test filtering of the options by requested options does not leave stray spacers at the start + * or end of a category and that a category does not contain two consecutive spacers. + * + * {@internal Careful! This test may need updates to still test what it is supposed to test + * if/when the defined options in Help::getAllOptions() change.} + * + * @param array $longOptions The long options which should be displayed. + * @param string $shortOptions The short options which should be displayed. + * + * @dataProvider dataOptionFilteringSpacerHandling + * + * @return void + */ + public function testOptionFilteringSpacerHandling($longOptions, $shortOptions) + { + $help = new Help(new ConfigDouble(), $longOptions, $shortOptions); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $activeOptions = $reflProperty->getValue($help); + $reflProperty->setAccessible(false); + + $this->assertNotEmpty($activeOptions, 'Active options is empty, test is invalid'); + + foreach ($activeOptions as $options) { + $first = reset($options); + $this->assertArrayNotHasKey('spacer', $first, 'Found spacer at start of category'); + + $last = end($options); + $this->assertArrayNotHasKey('spacer', $last, 'Found spacer at end of category'); + + $previousWasSpacer = false; + foreach ($options as $option) { + $this->assertFalse((isset($option['spacer']) && $previousWasSpacer === true), 'Consecutive spacers found'); + $previousWasSpacer = isset($option['spacer']); + } + } + + }//end testOptionFilteringSpacerHandling() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataOptionFilteringSpacerHandling() + { + return [ + 'No spacer at start of category' => [ + 'longOptions' => ['generator'], + 'shortOptions' => 'ie', + ], + 'No spacer at end of category' => [ + 'longOptions' => [ + 'encoding', + 'tab-width', + ], + 'shortOptions' => '', + ], + 'No consecutive spacers within category' => [ + 'longOptions' => [ + 'report', + 'report-file', + 'report-report', + 'report-width', + 'basepath', + 'ignore-annotations', + 'colors', + 'no-colors', + ], + 'shortOptions' => 'spqm', + ], + ]; + + }//end dataOptionFilteringSpacerHandling() + + + /** + * Test that if no short/long options are passed, only usage information is displayed (CS mode). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @dataProvider dataDisplayUsage + * + * @return void + */ + public function testDisplayUsageCS($cliArgs, $expectedRegex) + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expectedRegex = str_replace('phpc(bf|s)', 'phpcs', $expectedRegex); + $this->verifyDisplayUsage($cliArgs, $expectedRegex); + + }//end testDisplayUsageCS() + + + /** + * Test that if no short/long options are passed, only usage information is displayed (CBF mode). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @dataProvider dataDisplayUsage + * @group CBF + * + * @return void + */ + public function testDisplayUsageCBF($cliArgs, $expectedRegex) + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expectedRegex = str_replace('phpc(bf|s)', 'phpcbf', $expectedRegex); + $this->verifyDisplayUsage($cliArgs, $expectedRegex); + + }//end testDisplayUsageCBF() + + + /** + * Helper method to test that if no short/long options are passed, only usage information is displayed + * (and displayed correctly). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @return void + */ + private function verifyDisplayUsage($cliArgs, $expectedRegex) + { + $help = new Help(new ConfigDouble($cliArgs), []); + + $this->expectOutputRegex($expectedRegex); + + $help->display(); + + }//end verifyDisplayUsage() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataDisplayUsage() + { + return [ + 'Usage without colors' => [ + 'cliArgs' => ['--no-colors'], + 'expectedRegex' => '`^\s*Usage:\s+phpc(bf|s) \[options\] \\s+$`', + ], + 'Usage with colors' => [ + 'cliArgs' => ['--colors'], + 'expectedRegex' => '`^\s*\\033\[33mUsage:\\033\[0m\s+phpc(bf|s) \[options\] \\s+$`', + ], + ]; + + }//end dataDisplayUsage() + + + /** + * Test the column width calculations. + * + * This tests the following aspects: + * 1. That the report width is never less than Help::MIN_WIDTH, even when a smaller width is passed. + * 2. That the first column width is calculated correctly and is based on the longest argument. + * 3. That the word wrapping of the description respects the maximum report width. + * 4. That if the description is being wrapped, the indent for the second line is calculated correctly. + * + * @param int $reportWidth Report width for the test. + * @param array $longOptions The long options which should be displayed. + * @param string $expectedOutput Expected output. + * + * @dataProvider dataReportWidthCalculations + * + * @return void + */ + public function testReportWidthCalculations($reportWidth, $longOptions, $expectedOutput) + { + $config = new ConfigDouble(["--report-width=$reportWidth", '--no-colors']); + $help = new Help($config, $longOptions); + + $reflMethod = new ReflectionMethod($help, 'printCategories'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $this->expectOutputString($expectedOutput); + + }//end testReportWidthCalculations() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataReportWidthCalculations() + { + $longOptions = [ + 'e', + 'generator', + ]; + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'Report width small: 40; forces report width to minimum width of 60' => [ + 'reportWidth' => 40, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the'.PHP_EOL + .' names of all the sniffs it'.PHP_EOL + .' includes.'.PHP_EOL + .' --generator= Show documentation for a standard.'.PHP_EOL + .' Use either the "HTML", "Markdown"'.PHP_EOL + .' or "Text" generator.'.PHP_EOL, + ], + 'Report width is minimum: 60 (= self::MIN_WIDTH)' => [ + 'reportWidth' => Help::MIN_WIDTH, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the'.PHP_EOL + .' names of all the sniffs it'.PHP_EOL + .' includes.'.PHP_EOL + .' --generator= Show documentation for a standard.'.PHP_EOL + .' Use either the "HTML", "Markdown"'.PHP_EOL + .' or "Text" generator.'.PHP_EOL, + ], + 'Report width matches length for one line, not the other: 96; only one should wrap' => [ + 'reportWidth' => 96, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the names of all the sniffs it includes.'.PHP_EOL + .' --generator= Show documentation for a standard. Use either the "HTML", "Markdown"'.PHP_EOL + .' or "Text" generator.'.PHP_EOL, + ], + 'Report width matches longest line: 119; the messages should not wrap and there should be no stray new line at the end' => [ + 'reportWidth' => 119, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the names of all the sniffs it includes.'.PHP_EOL + .' --generator= Show documentation for a standard. Use either the "HTML", "Markdown" or "Text" generator.'.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataReportWidthCalculations() + + + /** + * Verify that variable elements in an argument specification get colorized correctly. + * + * @param string $input String to colorize. + * @param string $expected Expected function output. + * + * @dataProvider dataColorizeVariableInput + * + * @return void + */ + public function testColorizeVariableInput($input, $expected) + { + $help = new Help(new ConfigDouble(), []); + + $reflMethod = new ReflectionMethod($help, 'colorizeVariableInput'); + $reflMethod->setAccessible(true); + $result = $reflMethod->invoke($help, $input); + $reflMethod->setAccessible(false); + + $this->assertSame($expected, $result); + + }//end testColorizeVariableInput() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataColorizeVariableInput() + { + return [ + 'Empty string' => [ + 'input' => '', + 'expected' => '', + ], + 'String without variable element(s)' => [ + 'input' => 'This is text', + 'expected' => 'This is text', + ], + 'String with variable element' => [ + 'input' => 'This text', + 'expected' => "This \033[36m\033[32m text", + ], + 'String with multiple variable elements' => [ + 'input' => ' is ', + 'expected' => "\033[36m\033[32m is \033[36m\033[32m", + ], + 'String with unclosed variable element' => [ + 'input' => 'This 'This [ + 'input' => ' text>', + 'expected' => "\033[36m text>\033[32m", + ], + 'String with nested elements and surrounding text' => [ + 'input' => 'Start text> end', + 'expected' => "Start \033[36m text>\033[32m end", + ], + ]; + + }//end dataColorizeVariableInput() + + + /** + * Test the various option types within a category get displayed correctly. + * + * @param array> $input The options to print. + * @param array $expectedRegex Regexes to validate expected output. + * + * @dataProvider dataPrintCategoryOptions + * + * @return void + */ + public function testPrintCategoryOptionsNoColor($input, $expectedRegex) + { + $config = new ConfigDouble(['--no-colors']); + $help = new Help($config, []); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $reflProperty->setValue($help, ['cat' => $input]); + $reflProperty->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'setMaxOptionNameLength'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'printCategoryOptions'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help, $input); + $reflMethod->setAccessible(false); + + $this->expectOutputRegex($expectedRegex['no-color']); + + }//end testPrintCategoryOptionsNoColor() + + + /** + * Test the various option types within a category get displayed correctly. + * + * @param array> $input The options to print. + * @param array $expectedRegex Regexes to validate expected output. + * + * @dataProvider dataPrintCategoryOptions + * + * @return void + */ + public function testPrintCategoryOptionsColor($input, $expectedRegex) + { + $config = new ConfigDouble(['--colors']); + $help = new Help($config, []); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $reflProperty->setValue($help, ['cat' => $input]); + $reflProperty->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'setMaxOptionNameLength'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'printCategoryOptions'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help, $input); + $reflMethod->setAccessible(false); + + $this->expectOutputRegex($expectedRegex['color']); + + }//end testPrintCategoryOptionsColor() + + + /** + * Data provider. + * + * @return array>|array>> + */ + public static function dataPrintCategoryOptions() + { + $indentLength = strlen(Help::INDENT); + $gutterLength = strlen(Help::GUTTER); + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + // phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found -- Test readability is more important. + return [ + 'Input: arg, spacer, arg; new lines in description get preserved' => [ + 'input' => [ + 'short-option' => [ + 'argument' => '-a', + 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + ], + 'blank-line' => [ + 'spacer' => '', + ], + 'long-option-multi-line-description' => [ + 'argument' => '--something=', + 'description' => 'Proin sit amet malesuada libero, finibus bibendum tortor. Nulla vitae quam nec orci finibus pharetra.' + ."\n".'Nam eget blandit dui.', + ], + ], + 'expectedRegex' => [ + 'no-color' => '`^ {'.$indentLength.'}-a {15} {'.$gutterLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .'\R' + .' {'.$indentLength.'}--something= {'.$gutterLength.'}Proin sit amet malesuada libero, finibus bibendum tortor\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nulla vitae quam nec orci finibus pharetra\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nam eget blandit dui\.\R$`', + 'color' => '`^ {'.$indentLength.'}\\033\[32m-a {15}\\033\[0m {'.$gutterLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .'\R' + .' {'.$indentLength.'}\\033\[32m--something=\\033\[36m\\033\[32m\\033\[0m {'.$gutterLength.'}Proin sit amet malesuada libero, finibus bibendum tortor\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nulla vitae quam nec orci finibus pharetra\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nam eget blandit dui\.\R$`', + ], + ], + 'Input: text, arg, text; multi-line text gets wrapped' => [ + 'input' => [ + 'single-line-text' => [ + 'text' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + ], + 'argument-description' => [ + 'argument' => '--something', + 'description' => 'Fusce dapibus sodales est eu sodales.', + ], + 'multi-line-text-gets-wrapped' => [ + 'text' => 'Maecenas vulputate ligula vel feugiat finibus. Mauris sem dui, pretium in turpis auctor, consectetur ultrices lorem.', + ], + ], + 'expectedRegex' => [ + 'no-color' => '`^ {'.$indentLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .' {'.$indentLength.'}--something {'.$gutterLength.'}Fusce dapibus sodales est eu sodales\.\R' + .' {'.$indentLength.'}Maecenas vulputate ligula vel feugiat finibus. Mauris sem dui, pretium in\R' + .' {'.$indentLength.'}turpis auctor, consectetur ultrices lorem\.\R$`', + 'color' => '`^ {'.$indentLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .' {'.$indentLength.'}\\033\[32m--something\\033\[0m {'.$gutterLength.'}Fusce dapibus sodales est eu sodales\.\R' + .' {'.$indentLength.'}Maecenas vulputate ligula vel feugiat finibus. Mauris sem dui, pretium in\R' + .' {'.$indentLength.'}turpis auctor, consectetur ultrices lorem\.\R$`', + ], + ], + ]; + // phpcs:enable + + }//end dataPrintCategoryOptions() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/MessageCollector/MessageCollectorTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/MessageCollector/MessageCollectorTest.php new file mode 100644 index 00000000..faa98ca4 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/MessageCollector/MessageCollectorTest.php @@ -0,0 +1,538 @@ +expectException($exception); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $exceptionMsg); + } + + $msgCollector = new MessageCollector(); + $msgCollector->add($message); + + }//end testAddingNonStringMessageResultsInException() + + + /** + * Data provider. + * + * @see testAddingNonStringMessageResultsInException() + * + * @return array> + */ + public static function dataAddingNonStringMessageResultsInException() + { + return [ + 'null' => [null], + 'boolean' => [true], + 'integer' => [10], + 'array' => [['something' => 'incorrect']], + ]; + + }//end dataAddingNonStringMessageResultsInException() + + + /** + * Verify that passing a message type which is not one of the predefined types is rejected with an exception. + * + * @param mixed $type The invalid "type" to pass. + * + * @dataProvider dataAddingMessageWithUnsupportedMessageTypeResultsInException + * + * @return void + */ + public function testAddingMessageWithUnsupportedMessageTypeResultsInException($type) + { + $exception = 'InvalidArgumentException'; + $exceptionMsg = 'The message $type should be one of the predefined MessageCollector constants. Received: '; + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $exceptionMsg); + } + + $msgCollector = new MessageCollector(); + $msgCollector->add('Message', $type); + + }//end testAddingMessageWithUnsupportedMessageTypeResultsInException() + + + /** + * Data provider. + * + * @see testAddingMessageWithUnsupportedMessageTypeResultsInException() + * + * @return array> + */ + public static function dataAddingMessageWithUnsupportedMessageTypeResultsInException() + { + return [ + 'null' => [null], + 'boolean' => [true], + 'string' => ['DEPRECATED'], + 'integer which doesn\'t match any of the message type constants: -235' => [-235], + 'integer which doesn\'t match any of the message type constants: 0' => [0], + 'integer which doesn\'t match any of the message type constants: 3' => [3], + 'integer which doesn\'t match any of the message type constants: 6' => [6], + 'integer which doesn\'t match any of the message type constants: 123' => [123], + 'integer which doesn\'t match any of the message type constants: PHP_INT_MAX' => [PHP_INT_MAX], + ]; + + }//end dataAddingMessageWithUnsupportedMessageTypeResultsInException() + + + /** + * Verify that the `containsBlockingErrors()` method correctly identifies whether the collected messages + * include messages which are blocking (errors), or only include non-blocking (warnings, notices, + * deprecations) messages. + * + * @param array $messages The messages to display. + * Key is the message, value is the error level. + * @param bool $expected The expected function output. + * + * @dataProvider dataContainsBlockingErrors + * + * @return void + */ + public function testContainsBlockingErrors($messages, $expected) + { + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $this->assertSame($expected, $msgCollector->containsBlockingErrors()); + + }//end testContainsBlockingErrors() + + + /** + * Data provider. + * + * @see testContainsBlockingErrors() + * + * @return array|bool>> + */ + public static function dataContainsBlockingErrors() + { + return [ + 'No messages' => [ + 'messages' => [], + 'expected' => false, + ], + 'Only non-blocking messages' => [ + 'messages' => [ + 'First message' => MessageCollector::WARNING, + 'Second message' => MessageCollector::NOTICE, + 'Third message' => MessageCollector::DEPRECATED, + ], + 'expected' => false, + ], + 'Only blocking messages' => [ + 'messages' => [ + 'First message' => MessageCollector::ERROR, + 'Second message' => MessageCollector::ERROR, + 'Third message' => MessageCollector::ERROR, + ], + 'expected' => true, + ], + 'Mix of blocking and non-blocking messages' => [ + 'messages' => [ + 'First message' => MessageCollector::DEPRECATED, + 'Second message' => MessageCollector::ERROR, + 'Third message' => MessageCollector::WARNING, + ], + 'expected' => true, + ], + ]; + + }//end dataContainsBlockingErrors() + + + /** + * Test displaying non-blocking messages only. + * + * Verifies that: + * - Each message is prefixed with the appropriate prefix. + * - The default message order is observed. + * - The messages use the appropriate OS-specific EOL character. + * + * @param array $messages The messages to display. + * Key is the message, value is the error level. + * @param string $expected The expected exception message. + * + * @dataProvider dataDisplayingNonBlockingMessages + * + * @return void + */ + public function testDisplayingNonBlockingMessages($messages, $expected) + { + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $this->expectOutputString($expected); + + $msgCollector->display(); + + }//end testDisplayingNonBlockingMessages() + + + /** + * Data provider. + * + * @see testDisplayingNonBlockingMessages() + * + * @return array|string>> + */ + public static function dataDisplayingNonBlockingMessages() + { + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'No messages' => [ + 'messages' => [], + 'expected' => '', + ], + 'One warning' => [ + 'messages' => [ + 'This is a warning' => MessageCollector::WARNING, + ], + 'expected' => 'WARNING: This is a warning'.PHP_EOL.PHP_EOL, + ], + 'One notice' => [ + 'messages' => [ + 'This is a notice' => MessageCollector::NOTICE, + ], + 'expected' => 'NOTICE: This is a notice'.PHP_EOL.PHP_EOL, + ], + 'One deprecation' => [ + 'messages' => [ + 'This is a deprecation' => MessageCollector::DEPRECATED, + ], + 'expected' => 'DEPRECATED: This is a deprecation'.PHP_EOL.PHP_EOL, + ], + 'Multiple warnings' => [ + 'messages' => [ + 'First warning' => MessageCollector::WARNING, + 'Second warning' => MessageCollector::WARNING, + ], + 'expected' => 'WARNING: First warning'.PHP_EOL + .'WARNING: Second warning'.PHP_EOL.PHP_EOL, + ], + 'Multiple notices' => [ + 'messages' => [ + 'First notice' => MessageCollector::NOTICE, + 'Second notice' => MessageCollector::NOTICE, + 'Third notice' => MessageCollector::NOTICE, + ], + 'expected' => 'NOTICE: First notice'.PHP_EOL + .'NOTICE: Second notice'.PHP_EOL + .'NOTICE: Third notice'.PHP_EOL.PHP_EOL, + ], + 'Multiple deprecations' => [ + 'messages' => [ + 'First deprecation' => MessageCollector::DEPRECATED, + 'Second deprecation' => MessageCollector::DEPRECATED, + ], + 'expected' => 'DEPRECATED: First deprecation'.PHP_EOL + .'DEPRECATED: Second deprecation'.PHP_EOL.PHP_EOL, + ], + 'All together now' => [ + 'messages' => [ + 'First deprecation' => MessageCollector::DEPRECATED, + 'Second warning' => MessageCollector::WARNING, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth warning' => MessageCollector::WARNING, + ], + 'expected' => 'WARNING: Second warning'.PHP_EOL + .'WARNING: Fourth warning'.PHP_EOL + .'NOTICE: Third notice'.PHP_EOL + .'DEPRECATED: First deprecation'.PHP_EOL.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataDisplayingNonBlockingMessages() + + + /** + * Test displaying message collections containing blocking messages. + * + * Verifies that: + * - Each message is prefixed with the appropriate prefix. + * - The default message order is observed. + * - The messages use the appropriate OS-specific EOL character. + * + * @param array $messages The messages to display. + * Key is the message, value is the error level. + * @param string $expected The expected exception message. + * + * @dataProvider dataDisplayingBlockingErrors + * + * @return void + */ + public function testDisplayingBlockingErrors($messages, $expected) + { + $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($expected); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $expected); + } + + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + $msgCollector->display(); + + }//end testDisplayingBlockingErrors() + + + /** + * Data provider. + * + * @see testDisplayingBlockingErrors() + * + * @return array|string>> + */ + public static function dataDisplayingBlockingErrors() + { + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'Single error' => [ + 'messages' => [ + 'This is an error' => MessageCollector::ERROR, + ], + 'expected' => 'ERROR: This is an error'.PHP_EOL.PHP_EOL, + ], + 'Multiple errors' => [ + 'messages' => [ + 'First error' => MessageCollector::ERROR, + 'Second error' => MessageCollector::ERROR, + ], + 'expected' => 'ERROR: First error'.PHP_EOL + .'ERROR: Second error'.PHP_EOL.PHP_EOL, + ], + 'Errors mixed with non-blocking messages' => [ + 'messages' => [ + 'First deprecation' => MessageCollector::DEPRECATED, + 'Second warning' => MessageCollector::WARNING, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth error' => MessageCollector::ERROR, + 'Fifth warning' => MessageCollector::WARNING, + 'Sixth error' => MessageCollector::ERROR, + 'Seventh deprecation' => MessageCollector::DEPRECATED, + ], + 'expected' => 'ERROR: Fourth error'.PHP_EOL + .'ERROR: Sixth error'.PHP_EOL + .'WARNING: Second warning'.PHP_EOL + .'WARNING: Fifth warning'.PHP_EOL + .'NOTICE: Third notice'.PHP_EOL + .'DEPRECATED: First deprecation'.PHP_EOL + .'DEPRECATED: Seventh deprecation'.PHP_EOL.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataDisplayingBlockingErrors() + + + /** + * Verify and safeguard that adding the same message twice is accepted when messages have different error levels. + * + * Note: have multiple messages with the exact same text is not great for conveying information + * to the end-user, but that's not the concern of the MessageCollector class. + * + * @return void + */ + public function testNonUniqueMessagesWithDifferentErrorLevelAreAccepted() + { + $message = 'Trying to add the same message twice'; + $msgCollector = new MessageCollector(); + $msgCollector->add($message, MessageCollector::NOTICE); + $msgCollector->add($message, MessageCollector::WARNING); + + $expected = 'WARNING: Trying to add the same message twice'.PHP_EOL; + $expected .= 'NOTICE: Trying to add the same message twice'.PHP_EOL.PHP_EOL; + $this->expectOutputString($expected); + + $msgCollector->display(); + + }//end testNonUniqueMessagesWithDifferentErrorLevelAreAccepted() + + + /** + * Verify and safeguard that adding the same message twice is accepted when messages have the same error level. + * + * Note: have multiple messages with the exact same text is not great for conveying information + * to the end-user, but that's not the concern of the MessageCollector class. + * + * @return void + */ + public function testNonUniqueMessagesWithSameErrorLevelAreAccepted() + { + $message = 'Trying to add the same message twice'; + $msgCollector = new MessageCollector(); + $msgCollector->add($message, MessageCollector::NOTICE); + $msgCollector->add($message, MessageCollector::NOTICE); + + $expected = 'NOTICE: Trying to add the same message twice'.PHP_EOL; + $expected .= 'NOTICE: Trying to add the same message twice'.PHP_EOL.PHP_EOL; + $this->expectOutputString($expected); + + $msgCollector->display(); + + }//end testNonUniqueMessagesWithSameErrorLevelAreAccepted() + + + /** + * Ensure that the message cache is cleared when the collected messages are displayed. + * + * @return void + */ + public function testCallingDisplayTwiceWillNotShowMessagesTwice() + { + $messages = [ + 'First notice' => MessageCollector::NOTICE, + 'Second deprecation' => MessageCollector::DEPRECATED, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth warning' => MessageCollector::WARNING, + ]; + + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $expected = 'WARNING: Fourth warning'.PHP_EOL; + $expected .= 'NOTICE: First notice'.PHP_EOL; + $expected .= 'NOTICE: Third notice'.PHP_EOL; + $expected .= 'DEPRECATED: Second deprecation'.PHP_EOL.PHP_EOL; + $this->expectOutputString($expected); + + $msgCollector->display(); + $msgCollector->display(); + + }//end testCallingDisplayTwiceWillNotShowMessagesTwice() + + + /** + * Test that messages are ordered correctly. + * + * @param string $order The display order. + * @param string $expected The expected output. + * + * @dataProvider dataDisplayOrderHandling + * + * @return void + */ + public function testDisplayOrderHandling($order, $expected) + { + $messages = [ + 'First notice' => MessageCollector::NOTICE, + 'Second deprecation' => MessageCollector::DEPRECATED, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth warning' => MessageCollector::WARNING, + ]; + + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $this->expectOutputString($expected); + + $msgCollector->display($order); + + }//end testDisplayOrderHandling() + + + /** + * Data provider. + * + * @see testDisplayOrderHandling() + * + * @return array> + */ + public static function dataDisplayOrderHandling() + { + $expectedForSeverity = 'WARNING: Fourth warning'.PHP_EOL; + $expectedForSeverity .= 'NOTICE: First notice'.PHP_EOL; + $expectedForSeverity .= 'NOTICE: Third notice'.PHP_EOL; + $expectedForSeverity .= 'DEPRECATED: Second deprecation'.PHP_EOL.PHP_EOL; + + $expectedForReceived = 'NOTICE: First notice'.PHP_EOL; + $expectedForReceived .= 'DEPRECATED: Second deprecation'.PHP_EOL; + $expectedForReceived .= 'NOTICE: Third notice'.PHP_EOL; + $expectedForReceived .= 'WARNING: Fourth warning'.PHP_EOL.PHP_EOL; + + return [ + 'Order by severity' => [ + 'order' => MessageCollector::ORDERBY_SEVERITY, + 'expected' => $expectedForSeverity, + ], + 'Order by received' => [ + 'order' => MessageCollector::ORDERBY_RECEIVED, + 'expected' => $expectedForReceived, + ], + 'Invalid order defaults to severity' => [ + 'order' => 'unknown order', + 'expected' => $expectedForSeverity, + ], + ]; + + }//end dataDisplayOrderHandling() + + + /** + * Test helper. + * + * @param \PHP_CodeSniffer\Util\MessageCollector $collector The error cache object. + * @param array $messages The error messages to add to the cache. + * Key is the message, value is the error level. + * + * @return void + */ + private function createErrorCache(MessageCollector $collector, $messages) + { + foreach ($messages as $msg => $type) { + $collector->add($msg, $type); + } + + }//end createErrorCache() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/GetHumanReadableDurationTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/GetHumanReadableDurationTest.php new file mode 100644 index 00000000..93b3d05e --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/GetHumanReadableDurationTest.php @@ -0,0 +1,114 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Timing; + +use PHP_CodeSniffer\Util\Timing; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Timing::getHumanReadableDuration() method. + * + * @covers \PHP_CodeSniffer\Util\Timing::getHumanReadableDuration + */ +final class GetHumanReadableDurationTest extends TestCase +{ + + + /** + * Test the method. + * + * @param int|float $duration A duration in milliseconds. + * @param string $expected The expected human readable string. + * + * @dataProvider dataGetHumanReadableDuration + * + * @return void + */ + public function testGetHumanReadableDuration($duration, $expected) + { + $this->assertSame($expected, Timing::getHumanReadableDuration($duration)); + + }//end testGetHumanReadableDuration() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataGetHumanReadableDuration() + { + return [ + 'Duration: 0' => [ + 'duration' => 0, + 'expected' => '0ms', + ], + 'Duration: 13 milliseconds' => [ + 'duration' => 13.232101565, + 'expected' => '13ms', + ], + 'Duration: 14 milliseconds' => [ + 'duration' => 13.916015625, + 'expected' => '14ms', + ], + 'Duration: 999 milliseconds' => [ + 'duration' => 999.2236, + 'expected' => '999ms', + ], + 'Duration: 999+ milliseconds' => [ + 'duration' => 999.89236, + 'expected' => '1000ms', + ], + 'Duration: 1 second' => [ + 'duration' => 1000, + 'expected' => '1 secs', + ], + 'Duration: slightly more than 1 second' => [ + 'duration' => 1001.178215, + 'expected' => '1 secs', + ], + 'Duration: just under a 1 minute' => [ + 'duration' => 59999.3851, + 'expected' => '60 secs', + ], + 'Duration: exactly 1 minute' => [ + 'duration' => 60000, + 'expected' => '1 mins', + ], + 'Duration: slightly more than 1 minute' => [ + 'duration' => 60001.7581235, + 'expected' => '1 mins', + ], + 'Duration: 1 minute, just under half a second' => [ + 'duration' => 60499.83639, + 'expected' => '1 mins, 0.5 secs', + ], + 'Duration: 1 minute, just over half a second' => [ + 'duration' => 60501.961238, + 'expected' => '1 mins, 0.5 secs', + ], + 'Duration: 1 minute, 1 second' => [ + 'duration' => 61000, + 'expected' => '1 mins, 1 secs', + ], + 'Duration: exactly 1 hour' => [ + 'duration' => 3600000, + 'expected' => '60 mins', + ], + 'Duration: 89.4 mins' => [ + 'duration' => 5364000, + 'expected' => '89 mins, 24 secs', + ], + ]; + + }//end dataGetHumanReadableDuration() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/TimingTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/TimingTest.php new file mode 100644 index 00000000..87c2a649 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/TimingTest.php @@ -0,0 +1,121 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Timing; + +use PHP_CodeSniffer\Util\Timing; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Timing class. + * + * {@internal These tests need to run in separate processes as the Timing class uses static properties + * to keep track of the start time and whether or not the runtime has been printed and these + * can't be unset/reset once set.} + * + * @covers \PHP_CodeSniffer\Util\Timing + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ +final class TimingTest extends TestCase +{ + + + /** + * Verify that getDuration() returns 0 when the timer wasn't started. + * + * @return void + */ + public function testGetDurationWithoutStartReturnsZero() + { + $this->assertSame(0, Timing::getDuration()); + + }//end testGetDurationWithoutStartReturnsZero() + + + /** + * Verify that getDuration() returns the time in milliseconds. + * + * @return void + */ + public function testGetDurationWithStartReturnsMilliseconds() + { + Timing::startTiming(); + usleep(1500); + $duration = Timing::getDuration(); + + $this->assertTrue(is_float($duration)); + + }//end testGetDurationWithStartReturnsMilliseconds() + + + /** + * Verify that printRunTime() doesn't print anything if the timer wasn't started. + * + * @return void + */ + public function testTimeIsNotPrintedIfTimerWasNeverStarted() + { + $this->expectOutputString(''); + Timing::printRunTime(); + + }//end testTimeIsNotPrintedIfTimerWasNeverStarted() + + + /** + * Verify that printRunTime() doesn't print anything if the timer wasn't started. + * + * @return void + */ + public function testTimeIsNotPrintedIfTimerWasNeverStartedEvenWhenForced() + { + $this->expectOutputString(''); + Timing::printRunTime(true); + + }//end testTimeIsNotPrintedIfTimerWasNeverStartedEvenWhenForced() + + + /** + * Verify that printRunTime() when called multiple times only prints the runtime information once. + * + * @return void + */ + public function testTimeIsPrintedOnlyOnce() + { + $this->expectOutputRegex('`^Time: [0-9]+ms; Memory: [0-9\.]+MB'.PHP_EOL.PHP_EOL.'$`'); + + Timing::startTiming(); + usleep(2000); + Timing::printRunTime(); + Timing::printRunTime(); + Timing::printRunTime(); + + }//end testTimeIsPrintedOnlyOnce() + + + /** + * Verify that printRunTime() when called multiple times prints the runtime information multiple times if forced. + * + * @return void + */ + public function testTimeIsPrintedMultipleTimesOnlyIfForced() + { + $this->expectOutputRegex('`^(Time: [0-9]+ms; Memory: [0-9\.]+MB'.PHP_EOL.PHP_EOL.'){3}$`'); + + Timing::startTiming(); + usleep(2000); + Timing::printRunTime(true); + Timing::printRunTime(true); + Timing::printRunTime(true); + + }//end testTimeIsPrintedMultipleTimesOnlyIfForced() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/GetHighestWeightedTokenTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/GetHighestWeightedTokenTest.php new file mode 100644 index 00000000..e0bd014c --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/GetHighestWeightedTokenTest.php @@ -0,0 +1,162 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Tokens; + +use PHP_CodeSniffer\Util\Tokens; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Tokens::getHighestWeightedToken() method. + * + * @covers \PHP_CodeSniffer\Util\Tokens::getHighestWeightedToken + */ +final class GetHighestWeightedTokenTest extends TestCase +{ + + + /** + * Test the method. + * + * @param array $tokens The tokens to find the heighest weighted one. + * @param int|false $expected The expected function return value. + * + * @dataProvider dataGetHighestWeightedToken + * + * @return void + */ + public function testGetHighestWeightedToken($tokens, $expected) + { + $this->assertSame($expected, Tokens::getHighestWeightedToken($tokens)); + + }//end testGetHighestWeightedToken() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataGetHighestWeightedToken() + { + $data = [ + 'Array of non-tokens passed, returns first' => [ + 'tokens' => [ + PHP_SAPI, + PHP_MAJOR_VERSION, + PHP_OS, + ], + 'expected' => PHP_SAPI, + ], + 'No weightings available for any of the selected tokens, first one wins' => [ + 'tokens' => [ + T_VARIABLE, + T_STRING, + T_EXTENDS, + T_IMPLEMENTS, + ], + 'expected' => T_VARIABLE, + ], + 'single token always returns that token' => [ + 'tokens' => [T_VARIABLE], + 'expected' => T_VARIABLE, + ], + 'Unknown and known token, known token wins' => [ + 'tokens' => [ + T_VARIABLE, + T_SELF, + ], + 'expected' => T_SELF, + ], + 'Known and unknown token, known token wins' => [ + 'tokens' => [ + T_CLOSURE, + T_STRING, + ], + 'expected' => T_CLOSURE, + ], + 'Two tokens with equal weights passed, first one wins' => [ + 'tokens' => [ + T_CLOSURE, + T_FUNCTION, + ], + 'expected' => T_CLOSURE, + ], + 'Five tokens with equal weights passed, first one wins' => [ + 'tokens' => [ + T_NAMESPACE, + T_TRAIT, + T_ENUM, + T_CLASS, + T_INTERFACE, + ], + 'expected' => T_NAMESPACE, + ], + 'Tokens with different weights passed, heightest (25) wins' => [ + 'tokens' => [ + T_BITWISE_OR, + T_SELF, + T_MUL_EQUAL, + ], + 'expected' => T_SELF, + ], + 'Tokens with different weights passed, heightest (50) wins' => [ + 'tokens' => [ + T_BITWISE_XOR, + T_CATCH, + T_SPACESHIP, + T_PARENT, + ], + 'expected' => T_CATCH, + ], + ]; + + $high100 = [ + T_MULTIPLY, + T_BITWISE_AND, + T_SELF, + T_FOREACH, + T_CLOSURE, + ]; + $data['Tokens with different weights passed, ordered low-high, heightest (100) wins'] = [ + 'tokens' => $high100, + 'expected' => T_CLOSURE, + ]; + + shuffle($high100); + $data['Tokens with different weights passed, order random, heightest (100) wins'] = [ + 'tokens' => $high100, + 'expected' => T_CLOSURE, + ]; + + $high1000 = [ + T_ENUM, + T_FUNCTION, + T_ELSEIF, + T_PARENT, + T_BITWISE_OR, + T_MODULUS, + ]; + $data['Tokens with different weights passed, ordered low-high, heightest (1000) wins'] = [ + 'tokens' => $high1000, + 'expected' => T_ENUM, + ]; + + shuffle($high1000); + $data['Tokens with different weights passed, order random, heightest (1000) wins'] = [ + 'tokens' => $high1000, + 'expected' => T_ENUM, + ]; + + return $data; + + }//end dataGetHighestWeightedToken() + + +}//end class diff --git a/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/TokenNameTest.php b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/TokenNameTest.php new file mode 100644 index 00000000..43c6d695 --- /dev/null +++ b/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/TokenNameTest.php @@ -0,0 +1,197 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Tokens; + +use PHP_CodeSniffer\Util\Tokens; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Tokens::tokenName() method. + * + * @covers \PHP_CodeSniffer\Util\Tokens::tokenName + */ +final class TokenNameTest extends TestCase +{ + + + /** + * Test the method. + * + * @param int|string $tokenCode The PHP/PHPCS token code to get the name for. + * @param string $expected The expected token name. + * + * @dataProvider dataTokenName + * @dataProvider dataPolyfilledPHPNativeTokens + * + * @return void + */ + public function testTokenName($tokenCode, $expected) + { + $this->assertSame($expected, Tokens::tokenName($tokenCode)); + + }//end testTokenName() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataTokenName() + { + return [ + 'PHP native token: T_ECHO' => [ + 'tokenCode' => T_ECHO, + 'expected' => 'T_ECHO', + ], + 'PHP native token: T_FUNCTION' => [ + 'tokenCode' => T_FUNCTION, + 'expected' => 'T_FUNCTION', + ], + 'PHPCS native token: T_CLOSURE' => [ + 'tokenCode' => T_CLOSURE, + 'expected' => 'T_CLOSURE', + ], + 'PHPCS native token: T_STRING_CONCAT' => [ + 'tokenCode' => T_STRING_CONCAT, + 'expected' => 'T_STRING_CONCAT', + ], + + // Document the current behaviour for invalid input. + // This behaviour is subject to change. + 'Non-token integer passed' => [ + 'tokenCode' => 100000, + 'expected' => 'UNKNOWN', + ], + 'Non-token string passed' => [ + 'tokenCode' => 'something', + 'expected' => 'ing', + ], + ]; + + }//end dataTokenName() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataPolyfilledPHPNativeTokens() + { + return [ + 'PHP 5.5 native token, polyfilled: T_FINALLY' => [ + 'tokenCode' => T_FINALLY, + 'expected' => 'T_FINALLY', + ], + 'PHP 5.5 native token, polyfilled: T_YIELD' => [ + 'tokenCode' => T_YIELD, + 'expected' => 'T_YIELD', + ], + + 'PHP 5.6 native token, polyfilled: T_ELLIPSIS' => [ + 'tokenCode' => T_ELLIPSIS, + 'expected' => 'T_ELLIPSIS', + ], + 'PHP 5.6 native token, polyfilled: T_POW' => [ + 'tokenCode' => T_POW, + 'expected' => 'T_POW', + ], + 'PHP 5.6 native token, polyfilled: T_POW_EQUAL' => [ + 'tokenCode' => T_POW_EQUAL, + 'expected' => 'T_POW_EQUAL', + ], + + 'PHP 7.0 native token, polyfilled: T_SPACESHIP' => [ + 'tokenCode' => T_SPACESHIP, + 'expected' => 'T_SPACESHIP', + ], + 'PHP 7.0 native token, polyfilled: T_COALESCE' => [ + 'tokenCode' => T_COALESCE, + 'expected' => 'T_COALESCE', + ], + 'PHP 7.0 native token, polyfilled: T_YIELD_FROM' => [ + 'tokenCode' => T_YIELD_FROM, + 'expected' => 'T_YIELD_FROM', + ], + + 'PHP 7.4 native token, polyfilled: T_COALESCE_EQUAL' => [ + 'tokenCode' => T_COALESCE_EQUAL, + 'expected' => 'T_COALESCE_EQUAL', + ], + 'PHP 7.4 native token, polyfilled: T_BAD_CHARACTER' => [ + 'tokenCode' => T_BAD_CHARACTER, + 'expected' => 'T_BAD_CHARACTER', + ], + 'PHP 7.4 native token, polyfilled: T_FN' => [ + 'tokenCode' => T_FN, + 'expected' => 'T_FN', + ], + + 'PHP 8.0 native token, polyfilled: T_NULLSAFE_OBJECT_OPERATOR' => [ + 'tokenCode' => T_NULLSAFE_OBJECT_OPERATOR, + 'expected' => 'T_NULLSAFE_OBJECT_OPERATOR', + ], + 'PHP 8.0 native token, polyfilled: T_NAME_QUALIFIED' => [ + 'tokenCode' => T_NAME_QUALIFIED, + 'expected' => 'T_NAME_QUALIFIED', + ], + 'PHP 8.0 native token, polyfilled: T_NAME_FULLY_QUALIFIED' => [ + 'tokenCode' => T_NAME_FULLY_QUALIFIED, + 'expected' => 'T_NAME_FULLY_QUALIFIED', + ], + 'PHP 8.0 native token, polyfilled: T_NAME_RELATIVE' => [ + 'tokenCode' => T_NAME_RELATIVE, + 'expected' => 'T_NAME_RELATIVE', + ], + 'PHP 8.0 native token, polyfilled: T_MATCH' => [ + 'tokenCode' => T_MATCH, + 'expected' => 'T_MATCH', + ], + 'PHP 8.0 native token, polyfilled: T_ATTRIBUTE' => [ + 'tokenCode' => T_ATTRIBUTE, + 'expected' => 'T_ATTRIBUTE', + ], + + 'PHP 8.1 native token, polyfilled: T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG' => [ + 'tokenCode' => T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, + 'expected' => 'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG', + ], + 'PHP 8.1 native token, polyfilled: T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG' => [ + 'tokenCode' => T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, + 'expected' => 'T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG', + ], + 'PHP 8.1 native token, polyfilled: T_READONLY' => [ + 'tokenCode' => T_READONLY, + 'expected' => 'T_READONLY', + ], + 'PHP 8.1 native token, polyfilled: T_ENUM' => [ + 'tokenCode' => T_ENUM, + 'expected' => 'T_ENUM', + ], + + 'PHP 8.4 native token, polyfilled: T_PUBLIC_SET' => [ + 'tokenCode' => T_PUBLIC_SET, + 'expected' => 'T_PUBLIC_SET', + ], + 'PHP 8.4 native token, polyfilled: T_PROTECTED_SET' => [ + 'tokenCode' => T_PROTECTED_SET, + 'expected' => 'T_PROTECTED_SET', + ], + 'PHP 8.4 native token, polyfilled: T_PRIVATE_SET' => [ + 'tokenCode' => T_PRIVATE_SET, + 'expected' => 'T_PRIVATE_SET', + ], + ]; + + }//end dataPolyfilledPHPNativeTokens() + + +}//end class diff --git a/version.php b/version.php index 725817e1..8a1d365c 100644 --- a/version.php +++ b/version.php @@ -24,8 +24,8 @@ defined('MOODLE_INTERNAL') || die; -$plugin->version = 2025073000; -$plugin->release = '5.0.9'; +$plugin->version = 2025073001; +$plugin->release = '5.0.10'; $plugin->maturity = MATURITY_STABLE; $plugin->requires = 2019111803; // Moodle 3.8.3 release and upwards (first one supporting PHP 7.4). $plugin->component = 'local_codechecker';