Download project

This commit is contained in:
Roman Pyrih
2024-11-20 09:09:44 +01:00
parent 547a138d6a
commit 5ff041757f
40737 changed files with 7766183 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
<?php
/**
* A test class for running all PHP_CodeSniffer unit tests.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @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 ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests;
require_once 'Core/AllTests.php';
require_once 'Standards/AllSniffs.php';
// PHPUnit 7 made the TestSuite run() method incompatible with
// older PHPUnit versions due to return type hints, so maintain
// two different suite objects.
$phpunit7 = \false;
if (\class_exists('ps_metrics_module_v4_0_5\\PHPUnit\\Runner\\Version') === \true) {
$version = \ps_metrics_module_v4_0_5\PHPUnit\Runner\Version::id();
if (\version_compare($version, '7.0', '>=') === \true) {
$phpunit7 = \true;
}
}
if ($phpunit7 === \true) {
include_once 'TestSuite7.php';
} else {
include_once 'TestSuite.php';
}
class PHP_CodeSniffer_AllTests
{
/**
* Add all PHP_CodeSniffer test suites into a single test suite.
*
* @return \PHPUnit\Framework\TestSuite
*/
public static function suite()
{
$GLOBALS['PHP_CODESNIFFER_STANDARD_DIRS'] = [];
$GLOBALS['PHP_CODESNIFFER_TEST_DIRS'] = [];
// Use a special PHP_CodeSniffer test suite so that we can
// unset our autoload function after the run.
$suite = new TestSuite('PHP CodeSniffer');
$suite->addTest(Core\AllTests::suite());
$suite->addTest(Standards\AllSniffs::suite());
return $suite;
}
//end suite()
}
//end class

View File

@@ -0,0 +1,172 @@
<?php
/**
* Config class for use in the tests.
*
* The Config class contains a number of static properties.
* As the value of these static properties will be retained between instantiations of the class,
* config values set in one test can influence the results for another test, which makes tests unstable.
*
* This class is a "double" of the Config class which prevents this from happening.
* In _most_ cases, tests should be using this class instead of the "normal" Config,
* with the exception of select tests for the Config class itself.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2024 Juliette Reinders Folmer. All rights reserved.
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Config;
use ReflectionProperty;
final class ConfigDouble extends Config
{
/**
* Whether or not the setting of a standard should be skipped.
*
* @var boolean
*/
private $skipSettingStandard = \false;
/**
* Creates a clean Config object and populates it with command line values.
*
* @param array<string> $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->resetSelectProperties();
$this->preventReadingCodeSnifferConfFile();
parent::__construct($cliArgs);
if ($skipSettingReportWidth !== \true) {
$this->preventAutoDiscoveryScreenWidth();
}
}
//end __construct()
/**
* Sets the command line values and optionally prevents a file system search for a custom ruleset.
*
* @param array<string> $args An array of command line arguments to set.
*
* @return void
*/
public function setCommandLineValues($args)
{
parent::setCommandLineValues($args);
if ($this->skipSettingStandard !== \true) {
$this->preventSearchingForRuleset();
}
}
//end setCommandLineValues()
/**
* Reset a few properties on the Config class to their default values.
*
* @return void
*/
private function resetSelectProperties()
{
$this->setStaticConfigProperty('overriddenDefaults', []);
$this->setStaticConfigProperty('executablePaths', []);
}
//end resetSelectProperties()
/**
* 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.
*
* @return void
*/
private function preventReadingCodeSnifferConfFile()
{
$this->setStaticConfigProperty('configData', []);
$this->setStaticConfigProperty('configDataFile', '');
}
//end preventReadingCodeSnifferConfFile()
/**
* 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.
*
* @return void
*/
private function preventSearchingForRuleset()
{
$overriddenDefaults = $this->getStaticConfigProperty('overriddenDefaults');
if (isset($overriddenDefaults['standards']) === \false) {
$this->standards = ['PSR1'];
$overriddenDefaults['standards'] = \true;
}
self::setStaticConfigProperty('overriddenDefaults', $overriddenDefaults);
}
//end preventSearchingForRuleset()
/**
* 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.
*
* @return void
*/
private function preventAutoDiscoveryScreenWidth()
{
$settings = $this->getSettings();
if ($settings['reportWidth'] === 'auto') {
$this->reportWidth = self::DEFAULT_REPORT_WIDTH;
}
}
//end preventAutoDiscoveryScreenWidth()
/**
* Helper function to retrieve the value of a private static property on the Config class.
*
* @param string $name The name of the property to retrieve.
*
* @return mixed
*/
private function getStaticConfigProperty($name)
{
$property = new ReflectionProperty('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Config', $name);
$property->setAccessible(\true);
return $property->getValue();
}
//end getStaticConfigProperty()
/**
* Helper function to set the value of a private static property on the Config class.
*
* @param string $name The name of the property to set.
* @param mixed $value The value to set the property to.
*
* @return void
*/
private function setStaticConfigProperty($name, $value)
{
$property = new ReflectionProperty('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Config', $name);
$property->setAccessible(\true);
$property->setValue(null, $value);
$property->setAccessible(\false);
}
//end setStaticConfigProperty()
}
//end class

View File

@@ -0,0 +1,149 @@
<?php
/**
* Base class to use when testing utility methods.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2018-2019 Juliette Reinders Folmer. All rights reserved.
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\DummyFile;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Ruleset;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\ConfigDouble;
use ps_metrics_module_v4_0_5\PHPUnit\Framework\TestCase;
abstract class AbstractMethodUnitTest 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 static $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 static $tabWidth = 4;
/**
* The \PHP_CodeSniffer\Files\File object containing the parsed contents of the test case file.
*
* @var \PHP_CodeSniffer\Files\File
*/
protected static $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.
*
* @beforeClass
*
* @return void
*/
public static function initializeFile()
{
$_SERVER['argv'] = [];
$config = new ConfigDouble();
// Also set a tab-width to enable testing tab-replaced vs `orig_content`.
$config->tabWidth = static::$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 . '.' . static::$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);
self::$phpcsFile = new DummyFile($contents, $ruleset, $config);
self::$phpcsFile->parse();
}
//end initializeFile()
/**
* 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
*/
public function getTargetToken($commentString, $tokenType, $tokenContent = null)
{
return self::getTargetTokenFromFile(self::$phpcsFile, $commentString, $tokenType, $tokenContent);
}
//end getTargetToken()
/**
* 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 \PHP_CodeSniffer\Files\File $phpcsFile The file to find the token in.
* @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
*/
public static function getTargetTokenFromFile(File $phpcsFile, $commentString, $tokenType, $tokenContent = null)
{
$start = $phpcsFile->numTokens - 1;
$comment = $phpcsFile->findPrevious(\T_COMMENT, $start, null, \false, $commentString);
$tokens = $phpcsFile->getTokens();
$end = $start + 1;
// Limit the token finding to between this and the next delimiter comment.
for ($i = $comment + 1; $i < $end; $i++) {
if ($tokens[$i]['code'] !== \T_COMMENT) {
continue;
}
if (\stripos($tokens[$i]['content'], '/* test') === 0) {
$end = $i;
break;
}
}
$target = $phpcsFile->findNext($tokenType, $comment + 1, $end, \false, $tokenContent);
if ($target === \false) {
$msg = 'Failed to find test target token for comment string: ' . $commentString;
if ($tokenContent !== null) {
$msg .= ' With token content: ' . $tokenContent;
}
self::assertFalse(\true, $msg);
}
return $target;
}
//end getTargetTokenFromFile()
/**
* Helper method to tell PHPUnit to expect a PHPCS RuntimeException in a PHPUnit cross-version
* compatible manner.
*
* @param string $message The expected exception message.
*
* @return void
*/
public function expectRunTimeException($message)
{
$exception = 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Exceptions\\RuntimeException';
if (\method_exists($this, 'expectException') === \true) {
// PHPUnit 5+.
$this->expectException($exception);
$this->expectExceptionMessage($message);
} else {
// PHPUnit 4.
$this->setExpectedException($exception, $message);
}
}
//end expectRunTimeException()
}
//end class

View File

@@ -0,0 +1,52 @@
<?php
/**
* A test class for testing the core.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2006-2019 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\FileList;
use ps_metrics_module_v4_0_5\PHPUnit\Framework\TestSuite;
use ps_metrics_module_v4_0_5\PHPUnit\TextUI\TestRunner;
class AllTests
{
/**
* Prepare the test runner.
*
* @return void
*/
public static function main()
{
TestRunner::run(self::suite());
}
//end main()
/**
* Add all core unit tests into a test suite.
*
* @return \PHPUnit\Framework\TestSuite
*/
public static function suite()
{
$suite = new TestSuite('PHP CodeSniffer Core');
$testFileIterator = new FileList(__DIR__, '', '`Test\\.php$`Di');
foreach ($testFileIterator->fileIterator as $file) {
if (\strpos($file, 'AbstractMethodUnitTest.php') !== \false) {
continue;
}
include_once $file;
$class = \str_replace(__DIR__, '', $file);
$class = \str_replace('.php', '', $class);
$class = \str_replace('/', '\\', $class);
$class = 'PHP_CodeSniffer\\Tests\\Core' . $class;
$suite->addTestSuite($class);
}
return $suite;
}
//end suite()
}
//end class

View File

@@ -0,0 +1,66 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Autoload::determineLoadedClass method.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @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 ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Autoloader;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Autoload;
use ps_metrics_module_v4_0_5\PHPUnit\Framework\TestCase;
/**
* Tests for the \PHP_CodeSniffer\Autoload::determineLoadedClass method.
*
* @covers \PHP_CodeSniffer\Autoload::determineLoadedClass
*/
final class DetermineLoadedClassTest extends TestCase
{
/**
* Load the test files.
*
* @beforeClass
*
* @return void
*/
public static function includeFixture()
{
include __DIR__ . '/TestFiles/Sub/C.inc';
}
//end includeFixture()
/**
* Test for when class list is ordered.
*
* @return void
*/
public function testOrdered()
{
$classesBeforeLoad = ['classes' => [], 'interfaces' => [], 'traits' => []];
$classesAfterLoad = ['classes' => ['ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\A', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\B', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\C', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\Sub\\C'], 'interfaces' => [], 'traits' => []];
$className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad);
$this->assertEquals('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\Sub\\C', $className);
}
//end testOrdered()
/**
* Test for when class list is out of order.
*
* @return void
*/
public function testUnordered()
{
$classesBeforeLoad = ['classes' => [], 'interfaces' => [], 'traits' => []];
$classesAfterLoad = ['classes' => ['ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\A', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\Sub\\C', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\C', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\B'], 'interfaces' => [], 'traits' => []];
$className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad);
$this->assertEquals('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\Sub\\C', $className);
$classesAfterLoad = ['classes' => ['ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\A', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\C', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\Sub\\C', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\B'], 'interfaces' => [], 'traits' => []];
$className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad);
$this->assertEquals('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\Sub\\C', $className);
$classesAfterLoad = ['classes' => ['ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\Sub\\C', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\A', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\C', 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\B'], 'interfaces' => [], 'traits' => []];
$className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad);
$this->assertEquals('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\Autoloader\\Sub\\C', $className);
}
//end testUnordered()
}
//end class

View File

@@ -0,0 +1,3 @@
<?php
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
class A {}

View File

@@ -0,0 +1,4 @@
<?php
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
require 'A.inc';
class B extends A {}

View File

@@ -0,0 +1,4 @@
<?php
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
require 'B.inc';
class C extends B {}

View File

@@ -0,0 +1,5 @@
<?php
namespace PHP_CodeSniffer\Tests\Core\Autoloader\Sub;
require __DIR__.'/../C.inc';
use PHP_CodeSniffer\Tests\Core\Autoloader\C as ParentC;
class C extends ParentC {}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,230 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Config reportWidth value.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2006-2023 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Config;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Config;
use ps_metrics_module_v4_0_5\PHPUnit\Framework\TestCase;
use ReflectionProperty;
/**
* Tests for the \PHP_CodeSniffer\Config reportWidth value.
*
* @covers \PHP_CodeSniffer\Config::__get
*/
final class ReportWidthTest extends TestCase
{
/**
* Set static properties in the Config class to prevent tests influencing each other.
*
* @before
*
* @return void
*/
public static function cleanConfig()
{
// Set to the property's default value to clear out potentially set values from other tests.
self::setStaticProperty('executablePaths', []);
// Set to a usable value to circumvent Config trying to find a phpcs.xml config file.
self::setStaticProperty('overriddenDefaults', ['standards' => ['PSR1']]);
// Set to values which prevent the test-runner user's `CodeSniffer.conf` file
// from being read and influencing the tests.
self::setStaticProperty('configData', []);
self::setStaticProperty('configDataFile', '');
}
//end cleanConfig()
/**
* Clean up after each finished test.
*
* @after
*
* @return void
*/
public function resetConfig()
{
$_SERVER['argv'] = [];
}
//end resetConfig()
/**
* Reset the static properties in the Config class to their true defaults to prevent this class
* from influencing other tests.
*
* @afterClass
*
* @return void
*/
public static function resetConfigToDefaults()
{
self::setStaticProperty('overriddenDefaults', []);
self::setStaticProperty('executablePaths', []);
self::setStaticProperty('configData', null);
self::setStaticProperty('configDataFile', null);
$_SERVER['argv'] = [];
}
//end resetConfigToDefaults()
/**
* Test that report width without overrules will always be set to a non-0 positive integer.
*
* @covers \PHP_CodeSniffer\Config::__set
* @covers \PHP_CodeSniffer\Config::restoreDefaults
*
* @return void
*/
public function testReportWidthDefault()
{
$config = new Config();
// Can't test the exact value as "auto" will resolve differently depending on the machine running the tests.
$this->assertTrue(\is_int($config->reportWidth), 'Report width is not an integer');
$this->assertGreaterThan(0, $config->reportWidth, 'Report width is not greater than 0');
}
//end testReportWidthDefault()
/**
* Test that the report width will be set to a non-0 positive integer when not found in the CodeSniffer.conf file.
*
* @covers \PHP_CodeSniffer\Config::__set
* @covers \PHP_CodeSniffer\Config::restoreDefaults
*
* @return void
*/
public function testReportWidthWillBeSetFromAutoWhenNotFoundInConfFile()
{
$phpCodeSnifferConfig = ['default_standard' => 'PSR2', 'show_warnings' => '0'];
$this->setStaticProperty('configData', $phpCodeSnifferConfig);
$config = new Config();
// Can't test the exact value as "auto" will resolve differently depending on the machine running the tests.
$this->assertTrue(\is_int($config->reportWidth), 'Report width is not an integer');
$this->assertGreaterThan(0, $config->reportWidth, 'Report width is not greater than 0');
}
//end testReportWidthWillBeSetFromAutoWhenNotFoundInConfFile()
/**
* Test that the report width will be set correctly when found in the CodeSniffer.conf file.
*
* @covers \PHP_CodeSniffer\Config::__set
* @covers \PHP_CodeSniffer\Config::getConfigData
* @covers \PHP_CodeSniffer\Config::restoreDefaults
*
* @return void
*/
public function testReportWidthCanBeSetFromConfFile()
{
$phpCodeSnifferConfig = ['default_standard' => 'PSR2', 'report_width' => '120'];
$this->setStaticProperty('configData', $phpCodeSnifferConfig);
$config = new Config();
$this->assertSame(120, $config->reportWidth);
}
//end testReportWidthCanBeSetFromConfFile()
/**
* Test that the report width will be set correctly when passed as a CLI argument.
*
* @covers \PHP_CodeSniffer\Config::__set
* @covers \PHP_CodeSniffer\Config::processLongArgument
*
* @return void
*/
public function testReportWidthCanBeSetFromCLI()
{
$_SERVER['argv'] = ['phpcs', '--report-width=100'];
$config = new Config();
$this->assertSame(100, $config->reportWidth);
}
//end testReportWidthCanBeSetFromCLI()
/**
* Test that the report width will be set correctly when multiple report widths are passed on the CLI.
*
* @covers \PHP_CodeSniffer\Config::__set
* @covers \PHP_CodeSniffer\Config::processLongArgument
*
* @return void
*/
public function testReportWidthWhenSetFromCLIFirstValuePrevails()
{
$_SERVER['argv'] = ['phpcs', '--report-width=100', '--report-width=200'];
$config = new Config();
$this->assertSame(100, $config->reportWidth);
}
//end testReportWidthWhenSetFromCLIFirstValuePrevails()
/**
* Test that a report width passed as a CLI argument will overrule a report width set in a CodeSniffer.conf file.
*
* @covers \PHP_CodeSniffer\Config::__set
* @covers \PHP_CodeSniffer\Config::processLongArgument
* @covers \PHP_CodeSniffer\Config::getConfigData
*
* @return void
*/
public function testReportWidthSetFromCLIOverrulesConfFile()
{
$phpCodeSnifferConfig = ['default_standard' => 'PSR2', 'report_format' => 'summary', 'show_warnings' => '0', 'show_progress' => '1', 'report_width' => '120'];
$this->setStaticProperty('configData', $phpCodeSnifferConfig);
$cliArgs = ['phpcs', '--report-width=180'];
$config = new Config($cliArgs);
$this->assertSame(180, $config->reportWidth);
}
//end testReportWidthSetFromCLIOverrulesConfFile()
/**
* Test that the report width will be set to a non-0 positive integer when set to "auto".
*
* @covers \PHP_CodeSniffer\Config::__set
*
* @return void
*/
public function testReportWidthInputHandlingForAuto()
{
$config = new Config();
$config->reportWidth = 'auto';
// Can't test the exact value as "auto" will resolve differently depending on the machine running the tests.
$this->assertTrue(\is_int($config->reportWidth), 'Report width is not an integer');
$this->assertGreaterThan(0, $config->reportWidth, 'Report width is not greater than 0');
}
//end testReportWidthInputHandlingForAuto()
/**
* Test that the report width will be set correctly for various types of input.
*
* @param mixed $value Input value received.
* @param int $expected Expected report width.
*
* @dataProvider dataReportWidthInputHandling
* @covers \PHP_CodeSniffer\Config::__set
*
* @return void
*/
public function testReportWidthInputHandling($value, $expected)
{
$config = new Config();
$config->reportWidth = $value;
$this->assertSame($expected, $config->reportWidth);
}
//end testReportWidthInputHandling()
/**
* Data provider.
*
* @return array<string, array<string, mixed>>
*/
public static function dataReportWidthInputHandling()
{
return ['No value (empty string)' => ['value' => '', 'expected' => Config::DEFAULT_REPORT_WIDTH], 'Value: invalid input type null' => ['value' => null, 'expected' => Config::DEFAULT_REPORT_WIDTH], 'Value: invalid input type false' => ['value' => \false, 'expected' => Config::DEFAULT_REPORT_WIDTH], 'Value: invalid input type float' => ['value' => 100.5, 'expected' => Config::DEFAULT_REPORT_WIDTH], 'Value: invalid string value "invalid"' => ['value' => 'invalid', 'expected' => Config::DEFAULT_REPORT_WIDTH], 'Value: invalid string value, non-integer string "50.25"' => ['value' => '50.25', 'expected' => Config::DEFAULT_REPORT_WIDTH], 'Value: valid numeric string value' => ['value' => '250', 'expected' => 250], 'Value: valid int value' => ['value' => 220, 'expected' => 220], 'Value: negative int value becomes positive int' => ['value' => -180, 'expected' => 180]];
}
//end dataReportWidthInputHandling()
/**
* Helper function to set a static property on the Config class.
*
* @param string $name The name of the property to set.
* @param mixed $value The value to set the property to.
*
* @return void
*/
public static function setStaticProperty($name, $value)
{
$property = new ReflectionProperty('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Config', $name);
$property->setAccessible(\true);
$property->setValue(null, $value);
$property->setAccessible(\false);
}
//end setStaticProperty()
}
//end class

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,780 @@
<?php
/**
* Tests for PHP_CodeSniffer error suppression tags.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @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 ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\DummyFile;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Ruleset;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\ConfigDouble;
use ps_metrics_module_v4_0_5\PHPUnit\Framework\TestCase;
/**
* Tests for PHP_CodeSniffer error suppression tags.
*
* @covers PHP_CodeSniffer\Files\File::addMessage
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap
*/
final class ErrorSuppressionTest extends TestCase
{
/**
* Test suppressing a single error.
*
* @param string $before Annotation to place before the code.
* @param string $after Annotation to place after the code.
* @param int $expectedErrors Optional. Number of errors expected.
* Defaults to 0.
*
* @dataProvider dataSuppressError
*
* @return void
*/
public function testSuppressError($before, $after, $expectedErrors = 0)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.PHP.LowerCaseConstant'];
$ruleset = new Ruleset($config);
}
$content = '<?php ' . \PHP_EOL . $before . '$var = FALSE;' . \PHP_EOL . $after;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedErrors, $file->getErrorCount());
$this->assertCount($expectedErrors, $file->getErrors());
}
//end testSuppressError()
/**
* Data provider.
*
* @see testSuppressError()
*
* @return array<string, array<string, string|int>>
*/
public static function dataSuppressError()
{
return [
'no suppression' => ['before' => '', 'after' => '', 'expectedErrors' => 1],
// Inline slash comments.
'disable/enable: slash comment' => ['before' => '// phpcs:disable' . \PHP_EOL, 'after' => '// phpcs:enable'],
'disable/enable: multi-line slash comment, tab indented' => ['before' => "\t" . '// For reasons' . \PHP_EOL . "\t" . '// phpcs:disable' . \PHP_EOL . "\t", 'after' => "\t" . '// phpcs:enable'],
'disable/enable: slash comment, with @' => ['before' => '// @phpcs:disable' . \PHP_EOL, 'after' => '// @phpcs:enable'],
'disable/enable: slash comment, mixed case' => ['before' => '// PHPCS:Disable' . \PHP_EOL, 'after' => '// pHPcs:enabLE'],
// Inline hash comments.
'disable/enable: hash comment' => ['before' => '# phpcs:disable' . \PHP_EOL, 'after' => '# phpcs:enable'],
'disable/enable: multi-line hash comment, tab indented' => ['before' => "\t" . '# For reasons' . \PHP_EOL . "\t" . '# phpcs:disable' . \PHP_EOL . "\t", 'after' => "\t" . '# phpcs:enable'],
'disable/enable: hash comment, with @' => ['before' => '# @phpcs:disable' . \PHP_EOL, 'after' => '# @phpcs:enable'],
'disable/enable: hash comment, mixed case' => ['before' => '# PHPCS:Disable' . \PHP_EOL, 'after' => '# pHPcs:enabLE'],
// Inline star (block) comments.
'disable/enable: star comment' => ['before' => '/* phpcs:disable */' . \PHP_EOL, 'after' => '/* phpcs:enable */'],
'disable/enable: multi-line star comment' => ['before' => '/*' . \PHP_EOL . ' phpcs:disable' . \PHP_EOL . ' */' . \PHP_EOL, 'after' => '/*' . \PHP_EOL . ' phpcs:enable' . \PHP_EOL . ' */'],
'disable/enable: multi-line star comment, each line starred' => ['before' => '/*' . \PHP_EOL . ' * phpcs:disable' . \PHP_EOL . ' */' . \PHP_EOL, 'after' => '/*' . \PHP_EOL . ' * phpcs:enable' . \PHP_EOL . ' */'],
'disable/enable: multi-line star comment, each line starred, tab indented' => ['before' => "\t" . '/*' . \PHP_EOL . "\t" . ' * phpcs:disable' . \PHP_EOL . "\t" . ' */' . \PHP_EOL . "\t", 'after' => "\t" . '/*' . \PHP_EOL . ' * phpcs:enable' . \PHP_EOL . ' */'],
// Docblock comments.
'disable/enable: single line docblock comment' => ['before' => '/** phpcs:disable */' . \PHP_EOL, 'after' => '/** phpcs:enable */'],
// Deprecated syntax.
'old style: slash comment' => ['before' => '// @codingStandardsIgnoreStart' . \PHP_EOL, 'after' => '// @codingStandardsIgnoreEnd'],
'old style: star comment' => ['before' => '/* @codingStandardsIgnoreStart */' . \PHP_EOL, 'after' => '/* @codingStandardsIgnoreEnd */'],
'old style: multi-line star comment' => ['before' => '/*' . \PHP_EOL . ' @codingStandardsIgnoreStart' . \PHP_EOL . ' */' . \PHP_EOL, 'after' => '/*' . \PHP_EOL . ' @codingStandardsIgnoreEnd' . \PHP_EOL . ' */'],
'old style: single line docblock comment' => ['before' => '/** @codingStandardsIgnoreStart */' . \PHP_EOL, 'after' => '/** @codingStandardsIgnoreEnd */'],
];
}
//end dataSuppressError()
/**
* Test suppressing 1 out of 2 errors.
*
* @param string $before Annotation to place before the code.
* @param string $between Annotation to place between the code.
* @param int $expectedErrors Optional. Number of errors expected.
* Defaults to 1.
*
* @dataProvider dataSuppressSomeErrors
*
* @return void
*/
public function testSuppressSomeErrors($before, $between, $expectedErrors = 1)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.PHP.LowerCaseConstant'];
$ruleset = new Ruleset($config);
}
$content = <<<EOD
<?php
{$before}
\$var = FALSE;
{$between}
\$var = TRUE;
EOD;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedErrors, $file->getErrorCount());
$this->assertCount($expectedErrors, $file->getErrors());
}
//end testSuppressSomeErrors()
/**
* Data provider.
*
* @see testSuppressSomeErrors()
*
* @return array<string, array<string, string|int>>
*/
public static function dataSuppressSomeErrors()
{
return [
'no suppression' => ['before' => '', 'between' => '', 'expectedErrors' => 2],
// With suppression.
'disable/enable: slash comment' => ['before' => '// phpcs:disable', 'between' => '// phpcs:enable'],
'disable/enable: slash comment, with @' => ['before' => '// @phpcs:disable', 'between' => '// @phpcs:enable'],
'disable/enable: hash comment' => ['before' => '# phpcs:disable', 'between' => '# phpcs:enable'],
'disable/enable: hash comment, with @' => ['before' => '# @phpcs:disable', 'between' => '# @phpcs:enable'],
'disable/enable: single line docblock comment' => ['before' => '/** phpcs:disable */', 'between' => '/** phpcs:enable */'],
// Deprecated syntax.
'old style: slash comment' => ['before' => '// @codingStandardsIgnoreStart', 'between' => '// @codingStandardsIgnoreEnd'],
'old style: single line docblock comment' => ['before' => '/** @codingStandardsIgnoreStart */', 'between' => '/** @codingStandardsIgnoreEnd */'],
];
}
//end dataSuppressSomeErrors()
/**
* Test suppressing a single warning.
*
* @param string $before Annotation to place before the code.
* @param string $after Annotation to place after the code.
* @param int $expectedWarnings Optional. Number of warnings expected.
* Defaults to 0.
*
* @dataProvider dataSuppressWarning
*
* @return void
*/
public function testSuppressWarning($before, $after, $expectedWarnings = 0)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.Commenting.Todo'];
$ruleset = new Ruleset($config);
}
$content = <<<EOD
<?php
{$before}
//TODO: write some code.
{$after}
EOD;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedWarnings, $file->getWarningCount());
$this->assertCount($expectedWarnings, $file->getWarnings());
}
//end testSuppressWarning()
/**
* Data provider.
*
* @see testSuppressWarning()
*
* @return array<string, array<string, string|int>>
*/
public static function dataSuppressWarning()
{
return [
'no suppression' => ['before' => '', 'after' => '', 'expectedWarnings' => 1],
// With suppression.
'disable/enable: slash comment' => ['before' => '// phpcs:disable', 'after' => '// phpcs:enable'],
'disable/enable: slash comment, with @' => ['before' => '// @phpcs:disable', 'after' => '// @phpcs:enable'],
'disable/enable: single line docblock comment' => ['before' => '/** phpcs:disable */', 'after' => '/** phpcs:enable */'],
// Deprecated syntax.
'old style: slash comment' => ['before' => '// @codingStandardsIgnoreStart', 'after' => '// @codingStandardsIgnoreEnd'],
'old style: single line docblock comment' => ['before' => '/** @codingStandardsIgnoreStart */', 'after' => '/** @codingStandardsIgnoreEnd */'],
];
}
//end dataSuppressWarning()
/**
* Test suppressing a single error using a single line ignore.
*
* @param string $before Annotation to place before the code.
* @param string $after Optional. Annotation to place after the code.
* Defaults to an empty string.
* @param int $expectedErrors Optional. Number of errors expected.
* Defaults to 1.
*
* @dataProvider dataSuppressLine
*
* @return void
*/
public function testSuppressLine($before, $after = '', $expectedErrors = 1)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.PHP.LowerCaseConstant'];
$ruleset = new Ruleset($config);
}
$content = <<<EOD
<?php
{$before}
\$var = FALSE;{$after}
\$var = FALSE;
EOD;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedErrors, $file->getErrorCount());
$this->assertCount($expectedErrors, $file->getErrors());
}
//end testSuppressLine()
/**
* Data provider.
*
* @see testSuppressLine()
*
* @return array<string, array<string, string|int>>
*/
public static function dataSuppressLine()
{
return [
'no suppression' => ['before' => '', 'after' => '', 'expectedErrors' => 2],
// With suppression on line before.
'ignore: line before, slash comment' => ['before' => '// phpcs:ignore'],
'ignore: line before, slash comment, with @' => ['before' => '// @phpcs:ignore'],
'ignore: line before, hash comment' => ['before' => '# phpcs:ignore'],
'ignore: line before, hash comment, with @' => ['before' => '# @phpcs:ignore'],
'ignore: line before, star comment' => ['before' => '/* phpcs:ignore */'],
'ignore: line before, star comment, with @' => ['before' => '/* @phpcs:ignore */'],
// With suppression as trailing comment on code line.
'ignore: end of line, slash comment' => ['before' => '', 'after' => ' // phpcs:ignore'],
'ignore: end of line, slash comment, with @' => ['before' => '', 'after' => ' // @phpcs:ignore'],
'ignore: end of line, hash comment' => ['before' => '', 'after' => ' # phpcs:ignore'],
'ignore: end of line, hash comment, with @' => ['before' => '', 'after' => ' # @phpcs:ignore'],
// Deprecated syntax.
'old style: line before, slash comment' => ['before' => '// @codingStandardsIgnoreLine'],
'old style: end of line, slash comment' => ['before' => '', 'after' => ' // @codingStandardsIgnoreLine'],
];
}
//end dataSuppressLine()
/**
* Test suppressing a single error using a single line ignore in the middle of a line.
*
* @return void
*/
public function testSuppressLineMidLine()
{
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.PHP.LowerCaseConstant'];
$ruleset = new Ruleset($config);
$content = '<?php ' . \PHP_EOL . '$var = FALSE; /* @phpcs:ignore */ $var = FALSE;';
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame(0, $file->getErrorCount());
$this->assertCount(0, $file->getErrors());
}
//end testSuppressLineMidLine()
/**
* Test suppressing a single error using a single line ignore within a docblock.
*
* @return void
*/
public function testSuppressLineWithinDocblock()
{
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.Files.LineLength'];
$ruleset = new Ruleset($config);
// Process with @ suppression on line before inside docblock.
$comment = \str_repeat('a ', 50);
$content = <<<EOD
<?php
/**
* Comment here
* @phpcs:ignore
* {$comment}
*/
EOD;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame(0, $file->getErrorCount());
$this->assertCount(0, $file->getErrors());
}
//end testSuppressLineWithinDocblock()
/**
* Test that using a single line ignore does not interfere with other suppressions.
*
* @param string $before Annotation to place before the code.
* @param string $after Annotation to place after the code.
*
* @dataProvider dataNestedSuppressLine
*
* @return void
*/
public function testNestedSuppressLine($before, $after)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.PHP.LowerCaseConstant'];
$ruleset = new Ruleset($config);
}
$content = <<<EOD
<?php
{$before}
\$var = FALSE;
\$var = TRUE;
{$after}
EOD;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame(0, $file->getErrorCount());
$this->assertCount(0, $file->getErrors());
}
//end testNestedSuppressLine()
/**
* Data provider.
*
* @see testNestedSuppressLine()
*
* @return array<string, array<string, string>>
*/
public static function dataNestedSuppressLine()
{
return [
// Process with disable/enable suppression and no single line suppression.
'disable/enable: slash comment, no single line suppression' => ['before' => '// phpcs:disable', 'after' => '// phpcs:enable'],
'disable/enable: slash comment, with @, no single line suppression' => ['before' => '// @phpcs:disable', 'after' => '// @phpcs:enable'],
'disable/enable: hash comment, no single line suppression' => ['before' => '# phpcs:disable', 'after' => '# phpcs:enable'],
'old style: slash comment, no single line suppression' => ['before' => '// @codingStandardsIgnoreStart', 'after' => '// @codingStandardsIgnoreEnd'],
// Process with line suppression nested within disable/enable suppression.
'disable/enable: slash comment, next line nested single line suppression' => ['before' => '// phpcs:disable' . \PHP_EOL . '// phpcs:ignore', 'after' => '// phpcs:enable'],
'disable/enable: slash comment, with @, next line nested single line suppression' => ['before' => '// @phpcs:disable' . \PHP_EOL . '// @phpcs:ignore', 'after' => '// @phpcs:enable'],
'disable/enable: hash comment, next line nested single line suppression' => ['before' => '# @phpcs:disable' . \PHP_EOL . '# @phpcs:ignore', 'after' => '# @phpcs:enable'],
'old style: slash comment, next line nested single line suppression' => ['before' => '// @codingStandardsIgnoreStart' . \PHP_EOL . '// @codingStandardsIgnoreLine', 'after' => '// @codingStandardsIgnoreEnd'],
];
}
//end dataNestedSuppressLine()
/**
* Test suppressing a scope opener.
*
* @param string $before Annotation to place before the scope opener.
* @param string $after Annotation to place after the scope opener.
* @param int $expectedErrors Optional. Number of errors expected.
* Defaults to 0.
*
* @dataProvider dataSuppressScope
*
* @return void
*/
public function testSuppressScope($before, $after, $expectedErrors = 0)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['PEAR'];
$config->sniffs = ['PEAR.Functions.FunctionDeclaration'];
$ruleset = new Ruleset($config);
}
$content = '<?php ' . \PHP_EOL . $before . '$var = FALSE;' . $after . \PHP_EOL . '$var = FALSE;';
$content = <<<EOD
<?php
class MyClass() {
{$before}
function myFunction() {
{$after}
\$this->foo();
}
}
EOD;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedErrors, $file->getErrorCount());
$this->assertCount($expectedErrors, $file->getErrors());
}
//end testSuppressScope()
/**
* Data provider.
*
* @see testSuppressScope()
*
* @return array<string, array<string, string|int>>
*/
public static function dataSuppressScope()
{
return [
'no suppression' => ['before' => '', 'after' => '', 'expectedErrors' => 1],
// Process with suppression.
'disable/enable: slash comment' => ['before' => '//phpcs:disable', 'after' => '//phpcs:enable'],
'disable/enable: slash comment, with @' => ['before' => '//@phpcs:disable', 'after' => '//@phpcs:enable'],
'disable/enable: hash comment' => ['before' => '#phpcs:disable', 'after' => '#phpcs:enable'],
'disable/enable: single line docblock comment' => ['before' => '/** phpcs:disable */', 'after' => '/** phpcs:enable */'],
'disable/enable: single line docblock comment, with @' => ['before' => '/** @phpcs:disable */', 'after' => '/** @phpcs:enable */'],
// Deprecated syntax.
'old style: start/end, slash comment' => ['before' => '//@codingStandardsIgnoreStart', 'after' => '//@codingStandardsIgnoreEnd'],
'old style: start/end, single line docblock comment' => ['before' => '/** @codingStandardsIgnoreStart */', 'after' => '/** @codingStandardsIgnoreEnd */'],
];
}
//end dataSuppressScope()
/**
* Test suppressing a whole file.
*
* @param string $before Annotation to place before the code.
* @param string $after Optional. Annotation to place after the code.
* Defaults to an empty string.
* @param int $expectedWarnings Optional. Number of warnings expected.
* Defaults to 0.
*
* @dataProvider dataSuppressFile
*
* @return void
*/
public function testSuppressFile($before, $after = '', $expectedWarnings = 0)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.Commenting.Todo'];
$ruleset = new Ruleset($config);
}
$content = <<<EOD
<?php
{$before}
class MyClass {}
\$foo = new MyClass();
//TODO: write some code
{$after}
EOD;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedWarnings, $file->getWarningCount());
$this->assertCount($expectedWarnings, $file->getWarnings());
}
//end testSuppressFile()
/**
* Data provider.
*
* @see testSuppressFile()
*
* @return array<string, array<string, string|int>>
*/
public static function dataSuppressFile()
{
return [
'no suppression' => ['before' => '', 'after' => '', 'expectedWarnings' => 1],
// Process with suppression.
'ignoreFile: start of file, slash comment' => ['before' => '// phpcs:ignoreFile'],
'ignoreFile: start of file, slash comment, with @' => ['before' => '// @phpcs:ignoreFile'],
'ignoreFile: start of file, slash comment, mixed case' => ['before' => '// PHPCS:Ignorefile'],
'ignoreFile: start of file, hash comment' => ['before' => '# phpcs:ignoreFile'],
'ignoreFile: start of file, hash comment, with @' => ['before' => '# @phpcs:ignoreFile'],
'ignoreFile: start of file, single-line star comment' => ['before' => '/* phpcs:ignoreFile */'],
'ignoreFile: start of file, multi-line star comment' => ['before' => '/*' . \PHP_EOL . ' phpcs:ignoreFile' . \PHP_EOL . ' */'],
'ignoreFile: start of file, single-line docblock comment' => ['before' => '/** phpcs:ignoreFile */'],
// Process late comment.
'ignoreFile: late comment, slash comment' => ['before' => '', 'after' => '// phpcs:ignoreFile'],
// Deprecated syntax.
'old style: start of file, slash comment' => ['before' => '// @codingStandardsIgnoreFile'],
'old style: start of file, single-line star comment' => ['before' => '/* @codingStandardsIgnoreFile */'],
'old style: start of file, multi-line star comment' => ['before' => '/*' . \PHP_EOL . ' @codingStandardsIgnoreFile' . \PHP_EOL . ' */'],
'old style: start of file, single-line docblock comment' => ['before' => '/** @codingStandardsIgnoreFile */'],
// Deprecated syntax, late comment.
'old style: late comment, slash comment' => ['before' => '', 'after' => '// @codingStandardsIgnoreFile'],
];
}
//end dataSuppressFile()
/**
* Test disabling specific sniffs.
*
* @param string $before Annotation to place before the code.
* @param int $expectedErrors Optional. Number of errors expected.
* Defaults to 0.
* @param int $expectedWarnings Optional. Number of warnings expected.
* Defaults to 0.
*
* @dataProvider dataDisableSelected
*
* @return void
*/
public function testDisableSelected($before, $expectedErrors = 0, $expectedWarnings = 0)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.PHP.LowerCaseConstant', 'Generic.Commenting.Todo'];
$ruleset = new Ruleset($config);
}
$content = <<<EOD
<?php
{$before}
\$var = FALSE;
//TODO: write some code
EOD;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedErrors, $file->getErrorCount());
$this->assertCount($expectedErrors, $file->getErrors());
$this->assertSame($expectedWarnings, $file->getWarningCount());
$this->assertCount($expectedWarnings, $file->getWarnings());
}
//end testDisableSelected()
/**
* Data provider.
*
* @see testDisableSelected()
*
* @return array<string, array<string, string|int>>
*/
public static function dataDisableSelected()
{
return [
// Single sniff.
'disable: single sniff' => ['before' => '// phpcs:disable Generic.Commenting.Todo', 'expectedErrors' => 1],
'disable: single sniff with reason' => ['before' => '# phpcs:disable Generic.Commenting.Todo -- for reasons', 'expectedErrors' => 1],
'disable: single sniff, docblock' => ['before' => '/**' . \PHP_EOL . ' * phpcs:disable Generic.Commenting.Todo' . \PHP_EOL . ' */ ', 'expectedErrors' => 1],
'disable: single sniff, docblock, with @' => ['before' => '/**' . \PHP_EOL . ' * @phpcs:disable Generic.Commenting.Todo' . \PHP_EOL . ' */ ', 'expectedErrors' => 1],
// Multiple sniffs.
'disable: multiple sniffs in one comment' => ['before' => '// phpcs:disable Generic.Commenting.Todo,Generic.PHP.LowerCaseConstant'],
'disable: multiple sniff in multiple comments' => ['before' => '// phpcs:disable Generic.Commenting.Todo' . \PHP_EOL . '// phpcs:disable Generic.PHP.LowerCaseConstant'],
// Selectiveness variations.
'disable: complete category' => ['before' => '// phpcs:disable Generic.Commenting', 'expectedErrors' => 1],
'disable: whole standard' => ['before' => '// phpcs:disable Generic'],
'disable: single errorcode' => ['before' => '# @phpcs:disable Generic.Commenting.Todo.TaskFound', 'expectedErrors' => 1],
'disable: single errorcode and a category' => ['before' => '// phpcs:disable Generic.PHP.LowerCaseConstant.Found,Generic.Commenting'],
// Wrong category/sniff/code.
'disable: wrong error code and category' => ['before' => '/**' . \PHP_EOL . ' * phpcs:disable Generic.PHP.LowerCaseConstant.Upper,Generic.Comments' . \PHP_EOL . ' */ ', 'expectedErrors' => 1, 'expectedWarnings' => 1],
'disable: wrong category, docblock' => ['before' => '/**' . \PHP_EOL . ' * phpcs:disable Generic.Files' . \PHP_EOL . ' */ ', 'expectedErrors' => 1, 'expectedWarnings' => 1],
'disable: wrong category, docblock, with @' => ['before' => '/**' . \PHP_EOL . ' * @phpcs:disable Generic.Files' . \PHP_EOL . ' */ ', 'expectedErrors' => 1, 'expectedWarnings' => 1],
];
}
//end dataDisableSelected()
/**
* Test re-enabling specific sniffs that have been disabled.
*
* @param string $code Code pattern to check.
* @param int $expectedErrors Number of errors expected.
* @param int $expectedWarnings Number of warnings expected.
*
* @dataProvider dataEnableSelected
*
* @return void
*/
public function testEnableSelected($code, $expectedErrors, $expectedWarnings)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.PHP.LowerCaseConstant', 'Generic.Commenting.Todo'];
$ruleset = new Ruleset($config);
}
$content = '<?php ' . $code;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedErrors, $file->getErrorCount());
$this->assertCount($expectedErrors, $file->getErrors());
$this->assertSame($expectedWarnings, $file->getWarningCount());
$this->assertCount($expectedWarnings, $file->getWarnings());
}
//end testEnableSelected()
/**
* Data provider.
*
* @see testEnableSelected()
*
* @return array<string, array<string, string|int>>
*/
public static function dataEnableSelected()
{
return ['disable/enable: a single sniff' => ['code' => '
// phpcs:disable Generic.Commenting.Todo
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic.Commenting.Todo
//TODO: write some code', 'expectedErrors' => 1, 'expectedWarnings' => 1], 'disable/enable: multiple sniffs' => ['code' => '
// phpcs:disable Generic.Commenting.Todo,Generic.PHP.LowerCaseConstant
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic.Commenting.Todo,Generic.PHP.LowerCaseConstant
//TODO: write some code
$var = FALSE;', 'expectedErrors' => 1, 'expectedWarnings' => 1], 'disable: multiple sniffs; enable: one' => ['code' => '
# phpcs:disable Generic.Commenting.Todo,Generic.PHP.LowerCaseConstant
$var = FALSE;
//TODO: write some code
# phpcs:enable Generic.Commenting.Todo
//TODO: write some code
$var = FALSE;', 'expectedErrors' => 0, 'expectedWarnings' => 1], 'disable/enable: complete category' => ['code' => '
// phpcs:disable Generic.Commenting
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic.Commenting
//TODO: write some code', 'expectedErrors' => 1, 'expectedWarnings' => 1], 'disable/enable: whole standard' => ['code' => '
// phpcs:disable Generic
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic
//TODO: write some code', 'expectedErrors' => 0, 'expectedWarnings' => 1], 'disable: whole standard; enable: category from the standard' => ['code' => '
// phpcs:disable Generic
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic.Commenting
//TODO: write some code', 'expectedErrors' => 0, 'expectedWarnings' => 1], 'disable: a category; enable: the whole standard containing the category' => ['code' => '
# phpcs:disable Generic.Commenting
$var = FALSE;
//TODO: write some code
# phpcs:enable Generic
//TODO: write some code', 'expectedErrors' => 1, 'expectedWarnings' => 1], 'disable: single sniff; enable: the category containing the sniff' => ['code' => '
// phpcs:disable Generic.Commenting.Todo
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic.Commenting
//TODO: write some code', 'expectedErrors' => 1, 'expectedWarnings' => 1], 'disable: whole standard; enable: single sniff from the standard' => ['code' => '
// phpcs:disable Generic
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic.Commenting.Todo
//TODO: write some code', 'expectedErrors' => 0, 'expectedWarnings' => 1], 'disable: whole standard; enable: single sniff from the standard; disable: that same sniff; enable: everything' => ['code' => '
// phpcs:disable Generic
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic.Commenting.Todo
//TODO: write some code
// phpcs:disable Generic.Commenting.Todo
//TODO: write some code
// phpcs:enable
//TODO: write some code', 'expectedErrors' => 0, 'expectedWarnings' => 2], 'disable: whole standard; enable: single sniff from the standard; enable: other sniff from the standard' => ['code' => '
// phpcs:disable Generic
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic.Commenting.Todo
//TODO: write some code
$var = FALSE;
// phpcs:enable Generic.PHP.LowerCaseConstant
//TODO: write some code
$var = FALSE;', 'expectedErrors' => 1, 'expectedWarnings' => 2]];
}
//end dataEnableSelected()
/**
* Test ignoring specific sniffs.
*
* @param string $before Annotation to place before the code.
* @param int $expectedErrors Number of errors expected.
* @param int $expectedWarnings Number of warnings expected.
*
* @dataProvider dataIgnoreSelected
*
* @return void
*/
public function testIgnoreSelected($before, $expectedErrors, $expectedWarnings)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.PHP.LowerCaseConstant', 'Generic.Commenting.Todo'];
$ruleset = new Ruleset($config);
}
$content = <<<EOD
<?php
{$before}
\$var = FALSE; //TODO: write some code
\$var = FALSE; //TODO: write some code
EOD;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedErrors, $file->getErrorCount());
$this->assertCount($expectedErrors, $file->getErrors());
$this->assertSame($expectedWarnings, $file->getWarningCount());
$this->assertCount($expectedWarnings, $file->getWarnings());
}
//end testIgnoreSelected()
/**
* Data provider.
*
* @see testIgnoreSelected()
*
* @return array<string, array<string, string|int>>
*/
public static function dataIgnoreSelected()
{
return [
'no suppression' => ['before' => '', 'expectedErrors' => 2, 'expectedWarnings' => 2],
// With suppression.
'ignore: single sniff' => ['before' => '// phpcs:ignore Generic.Commenting.Todo', 'expectedErrors' => 2, 'expectedWarnings' => 1],
'ignore: multiple sniffs' => ['before' => '// phpcs:ignore Generic.Commenting.Todo,Generic.PHP.LowerCaseConstant', 'expectedErrors' => 1, 'expectedWarnings' => 1],
'disable: single sniff; ignore: single sniff' => ['before' => '// phpcs:disable Generic.Commenting.Todo' . \PHP_EOL . '// phpcs:ignore Generic.PHP.LowerCaseConstant', 'expectedErrors' => 1, 'expectedWarnings' => 0],
'ignore: category of sniffs' => ['before' => '# phpcs:ignore Generic.Commenting', 'expectedErrors' => 2, 'expectedWarnings' => 1],
'ignore: whole standard' => ['before' => '// phpcs:ignore Generic', 'expectedErrors' => 1, 'expectedWarnings' => 1],
];
}
//end dataIgnoreSelected()
/**
* Test ignoring specific sniffs.
*
* @param string $code Code pattern to check.
* @param int $expectedErrors Number of errors expected.
* @param int $expectedWarnings Number of warnings expected.
*
* @dataProvider dataCommenting
*
* @return void
*/
public function testCommenting($code, $expectedErrors, $expectedWarnings)
{
static $config, $ruleset;
if (isset($config, $ruleset) === \false) {
$config = new ConfigDouble();
$config->standards = ['Generic'];
$config->sniffs = ['Generic.PHP.LowerCaseConstant', 'Generic.Commenting.Todo'];
$ruleset = new Ruleset($config);
}
$content = '<?php ' . $code;
$file = new DummyFile($content, $ruleset, $config);
$file->process();
$this->assertSame($expectedErrors, $file->getErrorCount());
$this->assertCount($expectedErrors, $file->getErrors());
$this->assertSame($expectedWarnings, $file->getWarningCount());
$this->assertCount($expectedWarnings, $file->getWarnings());
}
//end testCommenting()
/**
* Data provider.
*
* @see testCommenting()
*
* @return array<string, array<string, string|int>>
*/
public static function dataCommenting()
{
return ['ignore: single sniff' => ['code' => '
// phpcs:ignore Generic.Commenting.Todo -- Because reasons
$var = FALSE; //TODO: write some code
$var = FALSE; //TODO: write some code', 'expectedErrors' => 2, 'expectedWarnings' => 1], 'disable: single sniff; enable: same sniff - test whitespace handling around reason delimiter' => ['code' => '
// phpcs:disable Generic.Commenting.Todo --Because reasons
$var = FALSE;
//TODO: write some code
// phpcs:enable Generic.Commenting.Todo -- Because reasons
//TODO: write some code', 'expectedErrors' => 1, 'expectedWarnings' => 1], 'disable: single sniff, multi-line comment' => ['code' => '
/*
Disable some checks
phpcs:disable Generic.Commenting.Todo
*/
$var = FALSE;
//TODO: write some code', 'expectedErrors' => 1, 'expectedWarnings' => 0], 'ignore: single sniff, multi-line slash comment' => ['code' => '
// Turn off a check for the next line of code.
// phpcs:ignore Generic.Commenting.Todo
$var = FALSE; //TODO: write some code
$var = FALSE; //TODO: write some code', 'expectedErrors' => 2, 'expectedWarnings' => 1], 'enable before disable, sniff not in standard' => ['code' => '
// phpcs:enable Generic.PHP.NoSilencedErrors -- Because reasons
$var = @delete( $filename );
', 'expectedErrors' => 0, 'expectedWarnings' => 0]];
}
//end dataCommenting()
}
//end class

View File

@@ -0,0 +1,105 @@
<?php
/* testSimpleAssignment */
$a = false;
/* testControlStructure */
while(true) {}
$a = 1;
/* testClosureAssignment */
$a = function($b=false;){};
/* testHeredocFunctionArg */
myFunction(<<<END
Foo
END
, 'bar');
/* testSwitch */
switch ($a) {
case 1: {break;}
default: {break;}
}
/* testStatementAsArrayValue */
$a = [new Datetime];
$a = array(new Datetime);
$a = new Datetime;
/* testUseGroup */
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
$a = [
/* testArrowFunctionArrayValue */
'a' => 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',
},
};

View File

@@ -0,0 +1,328 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File::findEndOfStatement method.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @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 ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
/**
* Tests for the \PHP_CodeSniffer\Files\File::findEndOfStatement method.
*
* @covers \PHP_CodeSniffer\Files\File::findEndOfStatement
*/
final class FindEndOfStatementTest extends AbstractMethodUnitTest
{
/**
* 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

View File

@@ -0,0 +1,52 @@
<?php
/* testNotAClass */
function notAClass() {}
/* testNonExtendedClass */
class testFECNNonExtendedClass {}
/* testExtendsUnqualifiedClass */
class testFECNExtendedClass extends testFECNClass {}
/* testExtendsFullyQualifiedClass */
class testFECNNamespacedClass extends \PHP_CodeSniffer\Tests\Core\File\testFECNClass {}
/* testExtendsPartiallyQualifiedClass */
class testFECNQualifiedClass extends Core\File\RelativeClass {}
/* testNonExtendedInterface */
interface testFECNInterface {}
/* testInterfaceExtendsUnqualifiedInterface */
interface testInterfaceThatExtendsInterface extends testFECNInterface{}
/* testInterfaceExtendsFullyQualifiedInterface */
interface testInterfaceThatExtendsFQCNInterface extends \PHP_CodeSniffer\Tests\Core\File\testFECNInterface{}
/* testExtendedAnonClass */
$anon = new class( $a, $b ) extends testFECNExtendedAnonClass {};
/* testNestedExtendedClass */
class testFECNNestedExtendedClass {
public function someMethod() {
/* testNestedExtendedAnonClass */
$anon = new class extends testFECNAnonClass {};
}
}
/* testClassThatExtendsAndImplements */
class testFECNClassThatExtendsAndImplements extends testFECNClass implements InterfaceA, InterfaceB {}
/* testClassThatImplementsAndExtends */
class testFECNClassThatImplementsAndExtends implements InterfaceA, InterfaceB extends testFECNClass {}
/* testInterfaceMultiExtends */
interface Multi extends \Package\FooInterface, \BarInterface {};
/* testMissingExtendsName */
class testMissingExtendsName extends { /* missing classname */ } // Intentional parse error.
// Intentional parse error. Has to be the last test in the file.
/* testParseError */
class testParseError extends testFECNClass

View File

@@ -0,0 +1,74 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File::findExtendedClassName method.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @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 ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\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<string, array<string, string|false>>
*/
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' => 'ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\File\\testFECNClass'], 'class extends partially qualified class' => ['identifier' => '/* testExtendsPartiallyQualifiedClass */', 'expected' => 'ps_metrics_module_v4_0_5\\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' => 'ps_metrics_module_v4_0_5\\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' => 'ps_metrics_module_v4_0_5\\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

View File

@@ -0,0 +1,47 @@
<?php
/* testNotAClass */
function notAClass() {}
/* testPlainInterface */
interface testFIINInterface {}
/* testNonImplementedClass */
class testFIINNonImplementedClass {}
/* testClassImplementsSingle */
class testFIINImplementedClass implements testFIINInterface {}
/* testClassImplementsMultiple */
class testFIINMultiImplementedClass implements testFIINInterface, testFIINInterface2 {}
/* testImplementsFullyQualified */
class testFIINNamespacedClass implements \PHP_CodeSniffer\Tests\Core\File\testFIINInterface {}
/* testImplementsPartiallyQualified */
class testFIINQualifiedClass implements Core\File\RelativeInterface {}
/* testClassThatExtendsAndImplements */
class testFECNClassThatExtendsAndImplements extends testFECNClass implements InterfaceA, \NameSpaced\Cat\InterfaceB {}
/* testClassThatImplementsAndExtends */
class testFECNClassThatImplementsAndExtends implements \InterfaceA, InterfaceB extends testFECNClass {}
/* testBackedEnumWithoutImplements */
enum Suit:string {}
/* testEnumImplementsSingle */
enum Suit implements Colorful {}
/* testBackedEnumImplementsMulti */
enum Suit: string implements Colorful, \Deck {}
/* testAnonClassImplementsSingle */
$anon = class() implements testFIINInterface {}
/* testMissingImplementsName */
class testMissingExtendsName implements { /* missing interface name */ } // Intentional parse error.
// Intentional parse error. Has to be the last test in the file.
/* testParseError */
class testParseError implements testInterface

View File

@@ -0,0 +1,73 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames method.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @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 ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\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<string>|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<string, array<string, string|array<string>>>
*/
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' => ['ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Tests\\Core\\File\\testFIINInterface']], 'class implements single interface, partially qualified' => ['identifier' => '/* testImplementsPartiallyQualified */', 'expected' => ['ps_metrics_module_v4_0_5\\Core\\File\\RelativeInterface']], 'class extends and implements' => ['identifier' => '/* testClassThatExtendsAndImplements */', 'expected' => ['InterfaceA', 'ps_metrics_module_v4_0_5\\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

View File

@@ -0,0 +1,164 @@
<?php
/* testSimpleAssignment */
$a = false;
/* testFunctionCall */
$a = doSomething();
/* testFunctionCallArgument */
$a = doSomething($a, $b);
/* testControlStructure */
while(true) {}
$a = 1;
/* testClosureAssignment */
$a = function($b=false;){};
/* testHeredocFunctionArg */
myFunction(<<<END
Foo
END
, 'bar');
switch ($a) {
case 1: {break;}
case 2: $foo = true; break;
default: {break;}
/* testSwitch */
}
/* testStatementAsArrayValue */
$a = [new Datetime];
$a = array(new Datetime);
$a = ['a' => $foo + $bar, 'b' => true];
/* testUseGroup */
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
$a = [
/* testArrowFunctionArrayValue */
'a' => fn() => return 1,
'b' => fn() => return 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 */
?>
<h1>Test</h1>
<?php echo '<h2>', foo(), '</h2>';
/* testOpenTagWithEcho */
?>
<h1>Test</h1>
<?= '<h2>', foo(), '</h2>';
$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 2;
case 2:
/* testInsideCaseContinueStatement */
continue 2;
case 3:
/* testInsideCaseReturnStatement */
return false;
case 4:
/* testInsideCaseExitStatement */
exit(1);
case 5:
/* testInsideCaseThrowStatement */
throw new Exception();
/* testDefaultStatement */
default:
/* testInsideDefaultContinueStatement */
continue $var;
}

View File

@@ -0,0 +1,454 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File:findStartOfStatement method.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @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 ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
/**
* Tests for the \PHP_CodeSniffer\Files\File:findStartOfStatement method.
*
* @covers \PHP_CodeSniffer\Files\File::findStartOfStatement
*/
final class FindStartOfStatementTest extends AbstractMethodUnitTest
{
/**
* 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 - 12, $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 - 9, $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<string, array<string, int|string>>
*/
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], '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()
}
//end class

View File

@@ -0,0 +1,58 @@
<?php
/* testNotAClass */
interface NotAClass {}
/* testAnonClass */
$anon = new class() {};
/* testEnum */
enum NotAClassEither {}
/* testClassWithoutProperties */
class ClassWithoutProperties {}
/* testAbstractClass */
abstract class AbstractClass {}
/* testFinalClass */
final class FinalClass {}
/* testReadonlyClass */
readonly class ReadOnlyClass {}
/* testFinalReadonlyClass */
final readonly class FinalReadOnlyClass extends Foo {}
/* testReadonlyFinalClass */
readonly /*comment*/ final class ReadOnlyFinalClass {}
/* testAbstractReadonlyClass */
abstract readonly class AbstractReadOnlyClass {}
/* testReadonlyAbstractClass */
readonly
abstract
class ReadOnlyAbstractClass {}
/* testWithCommentsAndNewLines */
abstract
/* comment */
class ClassWithCommentsAndNewLines {}
/* testWithDocblockWithoutProperties */
/**
* Class docblock.
*
* @package SomePackage
*
* @phpcs:disable Standard.Cat.SniffName -- Just because.
*/
class ClassWithDocblock {}
/* testParseErrorAbstractFinal */
final /* comment */
abstract // Intentional parse error, class cannot both be final and abstract.
class AbstractFinal {}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File:getClassProperties method.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\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<string, array<string, string|int>>
*/
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<string, bool> $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<string, array<string, string|array<string, bool|int>>>
*/
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

View File

@@ -0,0 +1,91 @@
<?php
/* testStartPoint */
/* condition 0: namespace */
namespace Conditions\HorribleCode {
/* condition 1: if */
if (!function_exists('letsGetSerious') ) {
/* condition 2: function */
function letsGetSerious() {
/* condition 3-1: if */
if (isset($loadthis)) {
doing_something();
/* condition 3-2: else */
} else {
/* condition 4: if */
if (!class_exists('SeriouslyNestedClass')) {
/* condition 5: nested class */
class SeriouslyNestedClass extends SomeOtherClass {
/* condition 6: class method */
public function SeriouslyNestedMethod(/* testSeriouslyNestedMethod */ $param) {
/* condition 7: switch */
switch ($param) {
/* condition 8a: case */
case 'testing':
/* condition 9: while */
while ($a < 10 ) {
/* condition 10-1: if */
if ($a === $b) {
/* condition 11-1: nested anonymous class */
return new class() {
/* condition 12: nested anonymous class method */
private function DidSomeoneSayNesting() {
/* condition 13: closure */
$c = function() {
/* testDeepestNested */
return 'closure';
};
}
};
/* condition 10-2: elseif */
} elseif($bool) {
echo 'hello world';
}
/* condition 10-3: foreach */
foreach ($array as $k => $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;
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,263 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File:getCondition and \PHP_CodeSniffer\Files\File:hasCondition methods.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2022-2024 PHPCSStandards Contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
use ps_metrics_module_v4_0_5\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<int|string, string>
*/
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<string>
*/
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<string, bool>
*/
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<string, int>
*/
protected static $testTokens = [];
/**
* Cache for the marker token stack pointers.
*
* @var array<string, int>
*/
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, Tokens::$ooScopeTokens);
$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<string, string> $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<string, array<string, string|array<string, string>>>
*/
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<string, string> $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<string, array<string, string|array<string, string>>>
*/
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<string, bool> $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<string, array<string, string|array<string, bool>>>
*/
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

View File

@@ -0,0 +1,23 @@
/* testInvalidTokenPassed */
print something;
var object =
{
/* testClosure */
propertyName: function () {}
}
/* testFunction */
function functionName() {}
/* testClass */
class ClassName
{
/* testMethod */
methodName() {
return false;
}
}
/* testFunctionUnicode */
function π() {}

View File

@@ -0,0 +1,113 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File::getDeclarationName method.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2022-2024 PHPCSStandards Contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\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<string, array<string, int|string>>
*/
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<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 GetDeclarationNameTest::testGetDeclarationName()
*
* @return array<string, array<string, string|array<int|string>>>
*/
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

View File

@@ -0,0 +1,102 @@
<?php
/* testInvalidTokenPassed */
echo MY_CONSTANT;
/* testClosure */
$closure = function() {};
/* testAnonClassWithParens */
$anonClass = new class() {};
/* testAnonClassWithParens2 */
$class = new class() {
private $property = 'test';
public function test() {}
};
/* testAnonClassWithoutParens */
$anonClass = new class {};
/* testAnonClassExtendsWithoutParens */
$class = new class extends SomeClass {
private $property = 'test';
public function test() {}
};
/* testFunction */
function functionName() {}
/* testFunctionReturnByRef */
function & functionNameByRef() {}
/* testClass */
abstract class ClassName {
/* testMethod */
public function methodName() {}
/* testAbstractMethod */
abstract protected function abstractMethodName();
/* testMethodReturnByRef */
private function &MethodNameByRef();
}
/* testExtendedClass */
class ExtendedClass extends Foo {}
/* testInterface */
interface InterfaceName {}
/* testTrait */
trait TraitName {
/* testFunctionEndingWithNumber */
function ValidNameEndingWithNumber5(){}
}
/* testClassWithNumber */
class ClassWith1Number implements SomeInterface {}
/* testInterfaceWithNumbers */
interface InterfaceWith12345Numbers extends AnotherInterface {}
/* testClassWithCommentsAndNewLines */
class /* comment */
// phpcs:ignore Standard.Cat.SniffName -- for reasons
ClassWithCommentsAndNewLines {}
/* testFunctionFn */
function fn() {}
/* testPureEnum */
enum Foo
{
case SOME_CASE;
}
/* testBackedEnumSpaceBetweenNameAndColon */
enum Hoo : string
{
case ONE = 'one';
case TWO = 'two';
}
/* testBackedEnumNoSpaceBetweenNameAndColon */
enum Suit: int implements Colorful, CardGame {}
/* testFunctionReturnByRefWithReservedKeywordEach */
function &each() {}
/* testFunctionReturnByRefWithReservedKeywordParent */
function &parent() {}
/* testFunctionReturnByRefWithReservedKeywordSelf */
function &self() {}
/* testFunctionReturnByRefWithReservedKeywordStatic */
function &static() {}
/* testLiveCoding */
// Intentional parse error. This has to be the last test in the file.
function // Comment.

View File

@@ -0,0 +1,95 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File::getDeclarationName method.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2022-2024 PHPCSStandards Contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\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<string, array<string, int|string>>
*/
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], 'live-coding' => ['testMarker' => '/* testLiveCoding */', 'targetType' => \T_FUNCTION]];
}
//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<string, array<string, string>>
*/
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

View File

@@ -0,0 +1,341 @@
<?php
class TestMemberProperties
{
/* testVar */
var $varA = true;
/* testVarType */
var ?int $varA = true;
/* testPublic */
public $varB = true;
/* testPublicType */
public string $varB = true;
/* testProtected */
protected $varC = true;
/* testProtectedType */
protected bool $varC = true;
/* testPrivate */
private $varD = true;
/* testPrivateType */
private array $varD = true;
/* testStatic */
static $varE = true;
/* testStaticType */
static ?string $varE = true;
/* testStaticVar */
static var $varF = true;
/* testVarStatic */
var static $varG = true;
/* testPublicStatic */
public // comment
// phpcs:ignore Stnd.Cat.Sniff -- For reasons.
static
$varH = true;
/* testProtectedStatic */
static protected $varI = true;
/* testPrivateStatic */
private static $varJ = true;
/* testNoPrefix */
$varK = true;
/* testPublicStaticWithDocblock */
/**
* Comment here.
*
* @phpcs:ignore Standard.Category.Sniff -- because
* @var boolean
*/
public static $varH = true;
/* testProtectedStaticWithDocblock */
/**
* Comment here.
*
* @phpcs:ignore Standard.Category.Sniff -- because
* @var boolean
*/
static protected $varI = true;
/* testPrivateStaticWithDocblock */
/**
* Comment here.
*
* @phpcs:ignore Standard.Category.Sniff -- because
* @var boolean
*/
private static $varJ = true;
public float
/* testGroupType 1 */
$x,
/* testGroupType 2 */
$y;
public static ?string
/* testGroupNullableType 1 */
$x = null,
/* testGroupNullableType 2 */
$y = null;
protected static
/* testGroupProtectedStatic 1 */
$varL,
/* testGroupProtectedStatic 2 */
$varM,
/* testGroupProtectedStatic 3 */
$varN;
private
/* testGroupPrivate 1 */
$varO = true,
/* testGroupPrivate 2 */
$varP = array( 'a' => '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;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
<?php
/* testParseError */
function missingOpenParens // Intentional parse error.

View File

@@ -0,0 +1,33 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2019-2024 PHPCSStandards Contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\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

View File

@@ -0,0 +1,4 @@
<?php
/* testParseError */
function missingCloseParens( // Intentional parse error.

View File

@@ -0,0 +1,33 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2019-2024 PHPCSStandards Contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\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

View File

@@ -0,0 +1,321 @@
<?php
/* testImportUse */
use Vendor\Package\Sub as Alias;
/* testImportGroupUse */
use Vendor\Package\Sub\{
ClassA,
ClassB as BAlias,
};
if ($foo) {}
/* testTraitUse */
class TraitUse {
use ImportedTrait;
function methodName() {}
}
/* testNotAFunction */
interface NotAFunction {};
/* testFunctionNoParams */
function noParams() {}
/* testPassByReference */
function passByReference(&$var) {}
/* testArrayHint */
function arrayHint(array $var) {}
/* testVariable */
function variable($var) {}
/* testSingleDefaultValue */
function defaultValue($var1=self::CONSTANT) {}
/* testDefaultValues */
function defaultValues($var1=1, $var2='value') {}
/* testTypeHint */
function typeHint(foo $var1, bar $var2) {}
class MyClass {
/* testSelfTypeHint */
function typeSelfHint(self $var) {}
}
/* testNullableTypeHint */
function nullableTypeHint(?int $var1, ?\bar $var2) {}
/* testBitwiseAndConstantExpressionDefaultValue */
function myFunction($a = 10 & 20) {}
/* testArrowFunction */
fn(int $a, ...$b) => $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 /* test */ = /* test */ 'default' /* test*/,
// 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,) {}
}
/* 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'),
) {}
/* testFunctionCallFnPHPCS353-354 */
$value = $obj->fn(true);
/* testClosureNoParams */
function() {};
/* testClosure */
function( $a = 'test' ) {};
/* testClosureUseNoParams */
function() use() {};
/* testClosureUse */
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

View File

@@ -0,0 +1,207 @@
<?php
/* testBasicFunction */
function myFunction() {}
/* testReturnFunction */
function myFunction(array ...$arrays): array
{
/* testNestedClosure */
return array_map(function(array $array): int {
return array_sum($array);
}, $arrays);
}
class MyClass {
/* testBasicMethod */
function myFunction() {}
/* testPrivateStaticMethod */
private static function myFunction() {}
/* testFinalMethod */
final public function myFunction() {}
/* testProtectedReturnMethod */
protected function myFunction() : int {}
/* testPublicReturnMethod */
public function myFunction(): array {}
/* testNullableReturnMethod */
public function myFunction(): ?array {}
/* testMessyNullableReturnMethod */
public function myFunction() /* comment
*/ :
/* comment */ ? // phpcs:ignore Stnd.Cat.Sniff -- For reasons.
array {}
/* testReturnNamespace */
function myFunction(): \MyNamespace\MyClass {}
/* testReturnMultilineNamespace */
// Parse error in PHP 8.0.
function myFunction(): \MyNamespace /** comment *\/ comment */
\MyClass /* comment */
\Foo {}
/* testReturnUnqualifiedName */
private function myFunction(): ?MyClass {}
/* testReturnPartiallyQualifiedName */
function myFunction(): Sub\Level\MyClass {}
}
abstract class MyClass
{
/* testAbstractMethod */
abstract function myFunction();
/* testAbstractReturnMethod */
abstract protected function myFunction(): bool;
}
interface MyInterface
{
/* testInterfaceMethod */
function myFunction();
}
$result = array_map(
/* testArrowFunction */
static fn(int $number) : int => $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 {}
/* 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

View File

@@ -0,0 +1,687 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File::getMethodProperties method.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @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 ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\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<int|string> $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<string, array<string, string|int|array<int|string>>>
*/
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' => 'ps_metrics_module_v4_0_5\\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 namespaces return type.
*
* @return void
*/
public function testReturnMultilineNamespace()
{
// Offsets are relative to the T_FUNCTION token.
$expected = ['scope' => 'public', 'scope_specified' => \false, 'return_type' => 'ps_metrics_module_v4_0_5\\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' => 'ps_metrics_module_v4_0_5\\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()
/**
* 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<string, string|int|bool> $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

View File

@@ -0,0 +1,25 @@
<?php
/* testNamespace */
namespace Foo\Bar\Baz;
/* testUseWithComments */
use Foo /*comment*/ \ Bar
// phpcs:ignore Stnd.Cat.Sniff -- For reasons.
\ Bah;
$cl = function() {
/* testCalculation */
return 1 + 2 +
// Comment.
3 + 4
+ 5 + 6 + 7 > 20;
}
/* testEchoWithTabs */
echo 'foo',
'bar' ,
'baz';
/* testEndOfFile */
echo $foo;

View File

@@ -0,0 +1,167 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Files\File::getTokensAsString method.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2022-2024 PHPCSStandards Contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\File;
use ps_metrics_module_v4_0_5\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<string, array<string, string|int>>
*/
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<string, array<string, string|int>>
*/
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

View File

@@ -0,0 +1,210 @@
<?php
/* testTokenizerIssue1971PHPCSlt330gt271A */
// This has to be the first test in the file!
[&$a, [$b, /* testTokenizerIssue1971PHPCSlt330gt271B */ &$c]] = $array;
/* testBitwiseAndA */
error_reporting( E_NOTICE & E_STRICT );
/* testBitwiseAndB */
$a = [ $something & $somethingElse ];
/* testBitwiseAndC */
$a = [ $first, $something & self::$somethingElse ];
/* testBitwiseAndD */
$a = array( $first, $something & $somethingElse );
/* testBitwiseAndE */
$a = [ 'a' => $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;
/* testTokenizerIssue1284PHPCSlt280A */
if ($foo) {}
[&$a, /* testTokenizerIssue1284PHPCSlt280B */ &$b] = $c;
/* testTokenizerIssue1284PHPCSlt280C */
if ($foo) {}
[&$a, $b];

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,200 @@
<?php
/**
* Abstract Testcase class for testing Filters.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2023 PHPCSStandards Contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Filters;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Filters\Filter;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Ruleset;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\ConfigDouble;
use ps_metrics_module_v4_0_5\PHPUnit\Framework\TestCase;
use RecursiveIteratorIterator;
/**
* Base functionality and utilities for testing Filter classes.
*/
abstract class AbstractFilterTestCase extends TestCase
{
/**
* The Config object.
*
* @var \PHP_CodeSniffer\Config
*/
protected static $config;
/**
* The Ruleset object.
*
* @var \PHP_CodeSniffer\Ruleset
*/
protected static $ruleset;
/**
* Initialize the config and ruleset objects.
*
* @beforeClass
*
* @return void
*/
public static function initializeConfigAndRuleset()
{
self::$config = new ConfigDouble(['--extensions=php,inc/php,js,css']);
self::$ruleset = new Ruleset(self::$config);
}
//end initializeConfigAndRuleset()
/**
* Helper method to retrieve a mock object for a Filter class.
*
* The `setMethods()` method was silently deprecated in PHPUnit 9 and removed in PHPUnit 10.
*
* Note: direct access to the `getMockBuilder()` method is soft deprecated as of PHPUnit 10,
* and expected to be hard deprecated in PHPUnit 11 and removed in PHPUnit 12.
* Dealing with that is something for a later iteration of the test suite.
*
* @param string $className Fully qualified name of the class under test.
* @param array<mixed> $constructorArgs Optional. Array of parameters to pass to the class constructor.
* @param array<string>|null $methodsToMock Optional. The methods to mock in the class under test.
* Needed for PHPUnit cross-version support as PHPUnit 4.x does
* not have a `setMethodsExcept()` method yet.
* If not passed, no methods will be replaced.
*
* @return \PHPUnit\Framework\MockObject\MockObject
*/
protected function getMockedClass($className, array $constructorArgs = [], $methodsToMock = null)
{
$mockedObj = $this->getMockBuilder($className);
if (\method_exists($mockedObj, 'onlyMethods') === \true) {
// PHPUnit 8+.
if (\is_array($methodsToMock) === \true) {
return $mockedObj->setConstructorArgs($constructorArgs)->onlyMethods($methodsToMock)->getMock();
}
return $mockedObj->getMock()->setConstructorArgs($constructorArgs);
}
// PHPUnit < 8.
return $mockedObj->setConstructorArgs($constructorArgs)->setMethods($methodsToMock)->getMock();
}
//end getMockedClass()
/**
* Retrieve an array of files which were accepted by a filter.
*
* @param \PHP_CodeSniffer\Filters\Filter $filter The Filter object under test.
*
* @return array<string>
*/
protected function getFilteredResultsAsArray(Filter $filter)
{
$iterator = new RecursiveIteratorIterator($filter);
$files = [];
foreach ($iterator as $file) {
$files[] = $file;
}
return $files;
}
//end getFilteredResultsAsArray()
/**
* Retrieve the basedir to use for tests using the `getFakeFileList()` method.
*
* @return string
*/
protected static function getBaseDir()
{
return \dirname(\dirname(\dirname(__DIR__)));
}
//end getBaseDir()
/**
* Retrieve a file list containing a range of paths for testing purposes.
*
* This list **must** contain files which exist in this project (well, except for some which don't exist
* purely for testing purposes), as `realpath()` is used in the logic under test and `realpath()` will
* return `false` for any non-existent files, which will automatically filter them out before
* we get to the code under test.
*
* Note this list does not include `.` and `..` as \PHP_CodeSniffer\Files\FileList uses `SKIP_DOTS`.
*
* @return array<string>
*/
protected static function getFakeFileList()
{
$basedir = self::getBaseDir();
return [
$basedir . '/.gitignore',
$basedir . '/.yamllint.yml',
$basedir . '/phpcs.xml',
$basedir . '/phpcs.xml.dist',
$basedir . '/autoload.php',
$basedir . '/bin',
$basedir . '/bin/phpcs',
$basedir . '/bin/phpcs.bat',
$basedir . '/scripts',
$basedir . '/scripts/build-phar.php',
$basedir . '/src',
$basedir . '/src/WillNotExist.php',
$basedir . '/src/WillNotExist.bak',
$basedir . '/src/WillNotExist.orig',
$basedir . '/src/Ruleset.php',
$basedir . '/src/Generators',
$basedir . '/src/Generators/Markdown.php',
$basedir . '/src/Standards',
$basedir . '/src/Standards/Generic',
$basedir . '/src/Standards/Generic/Docs',
$basedir . '/src/Standards/Generic/Docs/Classes',
$basedir . '/src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml',
$basedir . '/src/Standards/Generic/Sniffs',
$basedir . '/src/Standards/Generic/Sniffs/Classes',
$basedir . '/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php',
$basedir . '/src/Standards/Generic/Tests',
$basedir . '/src/Standards/Generic/Tests/Classes',
$basedir . '/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.1.inc',
// Will rarely exist when running the tests.
$basedir . '/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.1.inc.bak',
$basedir . '/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.2.inc',
$basedir . '/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.php',
$basedir . '/src/Standards/Squiz',
$basedir . '/src/Standards/Squiz/Docs',
$basedir . '/src/Standards/Squiz/Docs/WhiteSpace',
$basedir . '/src/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml',
$basedir . '/src/Standards/Squiz/Sniffs',
$basedir . '/src/Standards/Squiz/Sniffs/WhiteSpace',
$basedir . '/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php',
$basedir . '/src/Standards/Squiz/Tests',
$basedir . '/src/Standards/Squiz/Tests/WhiteSpace',
$basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc',
$basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed',
$basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js',
$basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed',
$basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php',
];
}
//end getFakeFileList()
/**
* Translate Linux paths to Windows paths, when necessary.
*
* These type of tests should be able to run and pass on both *nix as well as Windows
* based dev systems. This method is a helper to allow for this.
*
* @param array<string|array> $paths A single or multi-dimensional array containing
* file paths.
*
* @return array<string|array>
*/
protected static function mapPathsToRuntimeOs(array $paths)
{
if (\DIRECTORY_SEPARATOR !== '\\') {
return $paths;
}
foreach ($paths as $key => $value) {
if (\is_string($value) === \true) {
$paths[$key] = \strtr($value, '/', '\\\\');
} else {
if (\is_array($value) === \true) {
$paths[$key] = self::mapPathsToRuntimeOs($value);
}
}
}
return $paths;
}
//end mapPathsToRuntimeOs()
}
//end class

View File

@@ -0,0 +1,76 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Filters\Filter::accept method.
*
* @author Willington Vega <wvega@wvega.com>
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Filters\Filter;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Filters\Filter;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Ruleset;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\ConfigDouble;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase;
use RecursiveArrayIterator;
/**
* Tests for the \PHP_CodeSniffer\Filters\Filter::accept method.
*
* @covers \PHP_CodeSniffer\Filters\Filter
*/
final class AcceptTest extends AbstractFilterTestCase
{
/**
* Initialize the config and ruleset objects based on the `AcceptTest.xml` ruleset file.
*
* @beforeClass
*
* @return void
*/
public static function initializeConfigAndRuleset()
{
$standard = __DIR__ . '/' . \basename(__FILE__, '.php') . '.xml';
self::$config = new ConfigDouble(["--standard={$standard}", '--ignore=*/somethingelse/*']);
self::$ruleset = new Ruleset(self::$config);
}
//end initializeConfigAndRuleset()
/**
* Test filtering a file list for excluded paths.
*
* @param array<string> $inputPaths List of file paths to be filtered.
* @param array<string> $expectedOutput Expected filtering result.
*
* @dataProvider dataExcludePatterns
*
* @return void
*/
public function testExcludePatterns($inputPaths, $expectedOutput)
{
$fakeDI = new RecursiveArrayIterator($inputPaths);
$filter = new Filter($fakeDI, '/', self::$config, self::$ruleset);
$this->assertEquals($expectedOutput, $this->getFilteredResultsAsArray($filter));
}
//end testExcludePatterns()
/**
* Data provider.
*
* @see testExcludePatterns
*
* @return array<string, array<string, array<string>>>
*/
public static function dataExcludePatterns()
{
$testCases = [
// Test top-level exclude patterns.
'Non-sniff specific path based excludes from ruleset and command line are respected and don\'t filter out too much' => ['inputPaths' => ['/path/to/src/Main.php', '/path/to/src/Something/Main.php', '/path/to/src/Somethingelse/Main.php', '/path/to/src/SomethingelseEvenLonger/Main.php', '/path/to/src/Other/Main.php'], 'expectedOutput' => ['/path/to/src/Main.php', '/path/to/src/SomethingelseEvenLonger/Main.php']],
// Test ignoring standard/sniff specific exclude patterns.
'Filter should not act on standard/sniff specific exclude patterns' => ['inputPaths' => ['/path/to/src/generic-project/Main.php', '/path/to/src/generic/Main.php', '/path/to/src/anything-generic/Main.php'], 'expectedOutput' => ['/path/to/src/generic-project/Main.php', '/path/to/src/generic/Main.php', '/path/to/src/anything-generic/Main.php']],
];
// Allow these tests to work on Windows as well.
return self::mapPathsToRuntimeOs($testCases);
}
//end dataExcludePatterns()
}
//end class

View File

@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="AcceptTest" xsi:noNamespaceSchemaLocation="phpcs.xsd">
<description>Ruleset to test the filtering based on exclude patterns.</description>
<!-- Directory pattern. -->
<exclude-pattern>*/something/*</exclude-pattern>
<!-- File pattern. -->
<exclude-pattern>*/Other/Main\.php$</exclude-pattern>
<rule ref="Generic">
<!-- Standard specific directory pattern. -->
<exclude-pattern>/anything/*</exclude-pattern>
<!-- Standard specific file pattern. -->
<exclude-pattern>/YetAnother/Main\.php</exclude-pattern>
</rule>
</ruleset>

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,118 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Filters\GitModified class.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2023 PHPCSStandards Contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Filters;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Filters\GitModified;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase;
use RecursiveArrayIterator;
use ReflectionMethod;
/**
* Tests for the \PHP_CodeSniffer\Filters\GitModified class.
*
* @covers \PHP_CodeSniffer\Filters\GitModified
*/
final class GitModifiedTest extends AbstractFilterTestCase
{
/**
* Test filtering a file list for excluded paths.
*
* @return void
*/
public function testFileNamePassesAsBasePathWillTranslateToDirname()
{
$rootFile = self::getBaseDir() . '/autoload.php';
$fakeDI = new RecursiveArrayIterator(self::getFakeFileList());
$constructorArgs = [$fakeDI, $rootFile, self::$config, self::$ruleset];
$mockObj = $this->getMockedClass('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Filters\\GitModified', $constructorArgs, ['exec']);
$mockObj->expects($this->once())->method('exec')->willReturn(['autoload.php']);
$this->assertEquals([$rootFile], $this->getFilteredResultsAsArray($mockObj));
}
//end testFileNamePassesAsBasePathWillTranslateToDirname()
/**
* Test filtering a file list for excluded paths.
*
* @param array<string> $inputPaths List of file paths to be filtered.
* @param array<string> $outputGitModified Simulated "git modified" output.
* @param array<string> $expectedOutput Expected filtering result.
*
* @dataProvider dataAcceptOnlyGitModified
*
* @return void
*/
public function testAcceptOnlyGitModified($inputPaths, $outputGitModified, $expectedOutput)
{
$fakeDI = new RecursiveArrayIterator($inputPaths);
$constructorArgs = [$fakeDI, self::getBaseDir(), self::$config, self::$ruleset];
$mockObj = $this->getMockedClass('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Filters\\GitModified', $constructorArgs, ['exec']);
$mockObj->expects($this->once())->method('exec')->willReturn($outputGitModified);
$this->assertEquals($expectedOutput, $this->getFilteredResultsAsArray($mockObj));
}
//end testAcceptOnlyGitModified()
/**
* Data provider.
*
* @see testAcceptOnlyGitModified
*
* @return array<string, array<string, array<string>>>
*/
public static function dataAcceptOnlyGitModified()
{
$basedir = self::getBaseDir();
$fakeFileList = self::getFakeFileList();
$testCases = ['no files marked as git modified' => ['inputPaths' => $fakeFileList, 'outputGitModified' => [], 'expectedOutput' => []], 'files marked as git modified which don\'t actually exist' => ['inputPaths' => $fakeFileList, 'outputGitModified' => ['src/WillNotExist.php', 'src/WillNotExist.bak', 'src/WillNotExist.orig'], 'expectedOutput' => []], 'single file marked as git modified - file in root dir' => ['inputPaths' => $fakeFileList, 'outputGitModified' => ['autoload.php'], 'expectedOutput' => [$basedir . '/autoload.php']], 'single file marked as git modified - file in sub dir' => ['inputPaths' => $fakeFileList, 'outputGitModified' => ['src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php'], 'expectedOutput' => [$basedir . '/src', $basedir . '/src/Standards', $basedir . '/src/Standards/Generic', $basedir . '/src/Standards/Generic/Sniffs', $basedir . '/src/Standards/Generic/Sniffs/Classes', $basedir . '/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php']], 'multiple files marked as git modified, none valid for scan' => ['inputPaths' => $fakeFileList, 'outputGitModified' => ['.gitignore', 'phpcs.xml.dist', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed'], 'expectedOutput' => [$basedir . '/src', $basedir . '/src/Standards', $basedir . '/src/Standards/Squiz', $basedir . '/src/Standards/Squiz/Tests', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace']], 'multiple files marked as git modified, only one file valid for scan' => ['inputPaths' => $fakeFileList, 'outputGitModified' => ['.gitignore', 'src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml', 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php'], 'expectedOutput' => [$basedir . '/src', $basedir . '/src/Standards', $basedir . '/src/Standards/Generic', $basedir . '/src/Standards/Generic/Docs', $basedir . '/src/Standards/Generic/Docs/Classes', $basedir . '/src/Standards/Generic/Sniffs', $basedir . '/src/Standards/Generic/Sniffs/Classes', $basedir . '/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php']], 'multiple files marked as git modified, multiple files valid for scan' => ['inputPaths' => $fakeFileList, 'outputGitModified' => ['.yamllint.yml', 'autoload.php', 'src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php'], 'expectedOutput' => [$basedir . '/autoload.php', $basedir . '/src', $basedir . '/src/Standards', $basedir . '/src/Standards/Squiz', $basedir . '/src/Standards/Squiz/Sniffs', $basedir . '/src/Standards/Squiz/Sniffs/WhiteSpace', $basedir . '/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', $basedir . '/src/Standards/Squiz/Tests', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php']]];
return $testCases;
}
//end dataAcceptOnlyGitModified()
/**
* Test filtering a file list for excluded paths.
*
* @param string $cmd Command to run.
* @param array<string> $expected Expected return value.
*
* @dataProvider dataExecAlwaysReturnsArray
*
* @return void
*/
public function testExecAlwaysReturnsArray($cmd, $expected)
{
if (\is_dir(__DIR__ . '/../../../.git') === \false) {
$this->markTestSkipped('Not a git repository');
}
$fakeDI = new RecursiveArrayIterator(self::getFakeFileList());
$filter = new GitModified($fakeDI, '/', self::$config, self::$ruleset);
$reflMethod = new ReflectionMethod($filter, 'exec');
$reflMethod->setAccessible(\true);
$result = $reflMethod->invoke($filter, $cmd);
$this->assertSame($expected, $result);
}
//end testExecAlwaysReturnsArray()
/**
* Data provider.
*
* @see testExecAlwaysReturnsArray
*
* {@internal Missing: test with a command which yields a `false` return value.
* JRF: I've not managed to find a command which does so, let alone one, which then
* doesn't have side-effects of uncatchable output while running the tests.}
*
* @return array<string, array<string, string|array<string>>>
*/
public static function dataExecAlwaysReturnsArray()
{
return ['valid command which won\'t have any output unless files in the bin dir have been modified' => [
// Largely using the command used in the filter, but only checking the bin dir.
// This should prevent the test unexpectedly failing during local development (in most cases).
'cmd' => 'git ls-files -o -m --exclude-standard -- ' . \escapeshellarg(self::getBaseDir() . '/bin'),
'expected' => [],
], 'valid command which will have output' => ['cmd' => 'git ls-files --exclude-standard -- ' . \escapeshellarg(self::getBaseDir() . '/bin'), 'expected' => ['bin/phpcbf', 'bin/phpcbf.bat', 'bin/phpcs', 'bin/phpcs.bat']]];
}
//end dataExecAlwaysReturnsArray()
}
//end class

View File

@@ -0,0 +1,118 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Filters\GitStaged class.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2023 PHPCSStandards Contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Filters;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Filters\GitStaged;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase;
use RecursiveArrayIterator;
use ReflectionMethod;
/**
* Tests for the \PHP_CodeSniffer\Filters\GitStaged class.
*
* @covers \PHP_CodeSniffer\Filters\GitStaged
*/
final class GitStagedTest extends AbstractFilterTestCase
{
/**
* Test filtering a file list for excluded paths.
*
* @return void
*/
public function testFileNamePassesAsBasePathWillTranslateToDirname()
{
$rootFile = self::getBaseDir() . '/autoload.php';
$fakeDI = new RecursiveArrayIterator(self::getFakeFileList());
$constructorArgs = [$fakeDI, $rootFile, self::$config, self::$ruleset];
$mockObj = $this->getMockedClass('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Filters\\GitStaged', $constructorArgs, ['exec']);
$mockObj->expects($this->once())->method('exec')->willReturn(['autoload.php']);
$this->assertEquals([$rootFile], $this->getFilteredResultsAsArray($mockObj));
}
//end testFileNamePassesAsBasePathWillTranslateToDirname()
/**
* Test filtering a file list for excluded paths.
*
* @param array<string> $inputPaths List of file paths to be filtered.
* @param array<string> $outputGitStaged Simulated "git staged" output.
* @param array<string> $expectedOutput Expected filtering result.
*
* @dataProvider dataAcceptOnlyGitStaged
*
* @return void
*/
public function testAcceptOnlyGitStaged($inputPaths, $outputGitStaged, $expectedOutput)
{
$fakeDI = new RecursiveArrayIterator($inputPaths);
$constructorArgs = [$fakeDI, self::getBaseDir(), self::$config, self::$ruleset];
$mockObj = $this->getMockedClass('ps_metrics_module_v4_0_5\\PHP_CodeSniffer\\Filters\\GitStaged', $constructorArgs, ['exec']);
$mockObj->expects($this->once())->method('exec')->willReturn($outputGitStaged);
$this->assertEquals($expectedOutput, $this->getFilteredResultsAsArray($mockObj));
}
//end testAcceptOnlyGitStaged()
/**
* Data provider.
*
* @see testAcceptOnlyGitStaged
*
* @return array<string, array<string, array<string>>>
*/
public static function dataAcceptOnlyGitStaged()
{
$basedir = self::getBaseDir();
$fakeFileList = self::getFakeFileList();
$testCases = ['no files marked as git modified' => ['inputPaths' => $fakeFileList, 'outputGitStaged' => [], 'expectedOutput' => []], 'files marked as git modified which don\'t actually exist' => ['inputPaths' => $fakeFileList, 'outputGitStaged' => ['src/WillNotExist.php', 'src/WillNotExist.bak', 'src/WillNotExist.orig'], 'expectedOutput' => []], 'single file marked as git modified - file in root dir' => ['inputPaths' => $fakeFileList, 'outputGitStaged' => ['autoload.php'], 'expectedOutput' => [$basedir . '/autoload.php']], 'single file marked as git modified - file in sub dir' => ['inputPaths' => $fakeFileList, 'outputGitStaged' => ['src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php'], 'expectedOutput' => [$basedir . '/src', $basedir . '/src/Standards', $basedir . '/src/Standards/Generic', $basedir . '/src/Standards/Generic/Sniffs', $basedir . '/src/Standards/Generic/Sniffs/Classes', $basedir . '/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php']], 'multiple files marked as git modified, none valid for scan' => ['inputPaths' => $fakeFileList, 'outputGitStaged' => ['.gitignore', 'phpcs.xml.dist', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed'], 'expectedOutput' => [$basedir . '/src', $basedir . '/src/Standards', $basedir . '/src/Standards/Squiz', $basedir . '/src/Standards/Squiz/Tests', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace']], 'multiple files marked as git modified, only one file valid for scan' => ['inputPaths' => $fakeFileList, 'outputGitStaged' => ['.gitignore', 'src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml', 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php'], 'expectedOutput' => [$basedir . '/src', $basedir . '/src/Standards', $basedir . '/src/Standards/Generic', $basedir . '/src/Standards/Generic/Docs', $basedir . '/src/Standards/Generic/Docs/Classes', $basedir . '/src/Standards/Generic/Sniffs', $basedir . '/src/Standards/Generic/Sniffs/Classes', $basedir . '/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php']], 'multiple files marked as git modified, multiple files valid for scan' => ['inputPaths' => $fakeFileList, 'outputGitStaged' => ['.yamllint.yml', 'autoload.php', 'src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php'], 'expectedOutput' => [$basedir . '/autoload.php', $basedir . '/src', $basedir . '/src/Standards', $basedir . '/src/Standards/Squiz', $basedir . '/src/Standards/Squiz/Sniffs', $basedir . '/src/Standards/Squiz/Sniffs/WhiteSpace', $basedir . '/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', $basedir . '/src/Standards/Squiz/Tests', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', $basedir . '/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php']]];
return $testCases;
}
//end dataAcceptOnlyGitStaged()
/**
* Test filtering a file list for excluded paths.
*
* @param string $cmd Command to run.
* @param array<string> $expected Expected return value.
*
* @dataProvider dataExecAlwaysReturnsArray
*
* @return void
*/
public function testExecAlwaysReturnsArray($cmd, $expected)
{
if (\is_dir(__DIR__ . '/../../../.git') === \false) {
$this->markTestSkipped('Not a git repository');
}
$fakeDI = new RecursiveArrayIterator(self::getFakeFileList());
$filter = new GitStaged($fakeDI, '/', self::$config, self::$ruleset);
$reflMethod = new ReflectionMethod($filter, 'exec');
$reflMethod->setAccessible(\true);
$result = $reflMethod->invoke($filter, $cmd);
$this->assertSame($expected, $result);
}
//end testExecAlwaysReturnsArray()
/**
* Data provider.
*
* @see testExecAlwaysReturnsArray
*
* {@internal Missing: test with a command which yields a `false` return value.
* JRF: I've not managed to find a command which does so, let alone one, which then
* doesn't have side-effects of uncatchable output while running the tests.}
*
* @return array<string, array<string, array<string>>>
*/
public static function dataExecAlwaysReturnsArray()
{
return ['valid command which won\'t have any output unless files in the bin dir have been modified & staged' => [
// Largely using the command used in the filter, but only checking the bin dir.
// This should prevent the test unexpectedly failing during local development (in most cases).
'cmd' => 'git diff --cached --name-only -- ' . \escapeshellarg(self::getBaseDir() . '/bin'),
'expected' => [],
], 'valid command which will have output' => ['cmd' => 'git ls-files --exclude-standard -- ' . \escapeshellarg(self::getBaseDir() . '/bin'), 'expected' => ['bin/phpcbf', 'bin/phpcbf.bat', 'bin/phpcs', 'bin/phpcs.bat']]];
}
//end dataExecAlwaysReturnsArray()
}
//end class

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,10 @@
--- tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc
+++ PHP_CodeSniffer
@@ -5,7 +5,3 @@
if ($var) {
echo 'This line is tab indented';
}
-
-
-
-

View File

@@ -0,0 +1,11 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,9 @@
--- tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtStart.inc
+++ PHP_CodeSniffer
@@ -1,6 +1,3 @@
-
-
-
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;

View File

@@ -0,0 +1,10 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,8 @@
--- tests/Core/Fixer/Fixtures/GenerateDiffTest-LineAdded.inc
+++ PHP_CodeSniffer
@@ -1,4 +1,5 @@
<?php
+// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {

View File

@@ -0,0 +1,6 @@
<?php
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,8 @@
--- tests/Core/Fixer/Fixtures/GenerateDiffTest-LineRemoved.inc
+++ PHP_CodeSniffer
@@ -4,5 +4,4 @@
if ($var) {
echo 'This line is tab indented';
- echo 'And this line is not';
}

View File

@@ -0,0 +1,8 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
echo 'And this line is not';
}

View File

@@ -0,0 +1,7 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,9 @@
--- tests/Core/Fixer/Fixtures/GenerateDiffTest-NoTrailingWhitespace.inc
+++ PHP_CodeSniffer
@@ -1,5 +1,5 @@
<?php
-// Comment with 2 spaces trailing whitespace.
+// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {

View File

@@ -0,0 +1,7 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,9 @@
--- tests/Core/Fixer/Fixtures/GenerateDiffTest-TabsToSpaces.inc
+++ PHP_CodeSniffer
@@ -3,5 +3,5 @@
$var = FALSE;
if ($var) {
- echo 'This line is tab indented';
+ echo 'This line is tab indented';
}

View File

@@ -0,0 +1,7 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,12 @@
--- tests/Core/Fixer/Fixtures/GenerateDiffTest-VarNameChanged.inc
+++ PHP_CodeSniffer
@@ -1,7 +1,7 @@
<?php
// Comment with 2 spaces trailing whitespace.
-$rav = FALSE;
+$var = FALSE;
-if ($rav) {
+if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,7 @@
<?php
// Comment with 2 spaces trailing whitespace.
$rav = FALSE;
if ($rav) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,8 @@
--- tests/Core/Fixer/Fixtures/GenerateDiffTest-WhiteSpaceAtEnd.inc
+++ PHP_CodeSniffer
@@ -4,4 +4,4 @@
if ($var) {
echo 'This line is tab indented';
-}
+}

View File

@@ -0,0 +1,7 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,8 @@
--- tests/Core/Fixer/Fixtures/GenerateDiffTest-WhiteSpaceAtStart.inc
+++ PHP_CodeSniffer
@@ -1,4 +1,4 @@
- <?php
+<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;

View File

@@ -0,0 +1,7 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,7 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,7 @@
<?php
// Comment with 2 spaces trailing whitespace.
$var = FALSE;
if ($var) {
echo 'This line is tab indented';
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,168 @@
<?php
/**
* Tests for diff generation.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2024 Juliette Reinders Folmer. All rights reserved.
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Fixer;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\LocalFile;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Ruleset;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\ConfigDouble;
use ps_metrics_module_v4_0_5\PHPUnit\Framework\TestCase;
/**
* Tests for diff generation.
*
* Note: these tests are specifically about the Fixer::generateDiff() method and do not
* test running the fixer itself, nor generating a diff based on a fixer run.
*
* @covers PHP_CodeSniffer\Fixer::generateDiff
*/
final class GenerateDiffTest extends TestCase
{
/**
* A \PHP_CodeSniffer\Files\File object to compare the files against.
*
* @var \PHP_CodeSniffer\Files\LocalFile
*/
private static $phpcsFile;
/**
* Initialize an \PHP_CodeSniffer\Files\File object with code.
*
* Things to take note of in the code snippet used for these tests:
* - Line endings are \n.
* - Tab indent.
* - Trailing whitespace.
*
* Also note that the Config object is deliberately created without a `tabWidth` setting to
* prevent doing tab replacement when parsing the file. This is to allow for testing a
* diff with tabs vs spaces (which wouldn't yield a diff if tabs had already been replaced).
*
* @beforeClass
*
* @return void
*/
public static function initializeFile()
{
$config = new ConfigDouble();
$ruleset = new Ruleset($config);
self::$phpcsFile = new LocalFile(__DIR__ . '/Fixtures/GenerateDiffTest.inc', $ruleset, $config);
self::$phpcsFile->parse();
self::$phpcsFile->fixer->startFile(self::$phpcsFile);
}
//end initializeFile()
/**
* Test generating a diff on the file object itself.
*
* @return void
*/
public function testGenerateDiffNoFile()
{
$diff = self::$phpcsFile->fixer->generateDiff(null, \false);
$this->assertSame('', $diff);
}
//end testGenerateDiffNoFile()
/**
* Test generating a diff between a PHPCS File object and a file on disk.
*
* @param string $filePath The path to the file to compare the File object against.
*
* @dataProvider dataGenerateDiff
*
* @return void
*/
public function testGenerateDiff($filePath)
{
$diff = self::$phpcsFile->fixer->generateDiff($filePath, \false);
// Allow for the tests to pass on Windows too.
$diff = \str_replace('--- tests\\Core\\Fixer/', '--- tests/Core/Fixer/', $diff);
$expectedDiffFile = \str_replace('.inc', '.diff', $filePath);
$this->assertStringEqualsFile($expectedDiffFile, $diff);
}
//end testGenerateDiff()
/**
* Data provider.
*
* @see testGenerateDiff()
*
* @return array<string, array<string, string>>
*/
public static function dataGenerateDiff()
{
return ['no difference' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-NoDiff.inc'], 'line removed' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-LineRemoved.inc'], 'line added' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-LineAdded.inc'], 'var name changed' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-VarNameChanged.inc'], 'trailing whitespace removed' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-NoTrailingWhitespace.inc'], 'tab replaced with spaces' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-TabsToSpaces.inc'], 'blank lines at start of file' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-BlankLinesAtStart.inc'], 'whitespace diff at start of file' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-WhiteSpaceAtStart.inc'], 'blank lines at end of file' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc'], 'whitespace diff at end of file' => ['filePath' => __DIR__ . '/Fixtures/GenerateDiffTest-WhiteSpaceAtEnd.inc']];
}
//end dataGenerateDiff()
/**
* Test generating a diff between a PHPCS File object and a file on disk and colourizing the output.
*
* @return void
*/
public function testGenerateDiffColoured()
{
$expected = "\x1b[31m--- tests/Core/Fixer/Fixtures/GenerateDiffTest-VarNameChanged.inc\x1b[0m" . \PHP_EOL;
$expected .= "\x1b[32m+++ PHP_CodeSniffer\x1b[0m" . \PHP_EOL;
$expected .= '@@ -1,7 +1,7 @@' . \PHP_EOL;
$expected .= ' <?php' . \PHP_EOL;
$expected .= ' // Comment with 2 spaces trailing whitespace. ' . \PHP_EOL;
$expected .= "\x1b[31m" . '-$rav = FALSE;' . "\x1b[0m" . \PHP_EOL;
$expected .= "\x1b[32m" . '+$var = FALSE;' . "\x1b[0m" . \PHP_EOL;
$expected .= ' ' . \PHP_EOL;
$expected .= "\x1b[31m" . '-if ($rav) {' . "\x1b[0m" . \PHP_EOL;
$expected .= "\x1b[32m" . '+if ($var) {' . "\x1b[0m" . \PHP_EOL;
$expected .= ' echo \'This line is tab indented\';' . \PHP_EOL;
$expected .= ' }';
$filePath = __DIR__ . '/Fixtures/GenerateDiffTest-VarNameChanged.inc';
$diff = self::$phpcsFile->fixer->generateDiff($filePath);
// Allow for the tests to pass on Windows too.
$diff = \str_replace('--- tests\\Core\\Fixer/', '--- tests/Core/Fixer/', $diff);
$this->assertSame($expected, $diff);
}
//end testGenerateDiffColoured()
/**
* Test generating a diff between a PHPCS File object using *nix line endings and a file on disk
* using Windows line endings.
*
* The point of this test is to verify that all lines are marked as having a difference.
* The actual lines endings used in the diff shown to the end-user are not relevant for this
* test.
* As the "diff" command is finicky with what type of line endings are used when the only
* difference on a line is the line ending, the test normalizes the line endings of the
* received diff before testing it.
*
* @return void
*/
public function testGenerateDiffDifferentLineEndings()
{
// By the looks of it, if the only diff between two files is line endings, the
// diff generated by the *nix "diff" command will always contain *nix line endings.
$expected = '--- tests/Core/Fixer/Fixtures/GenerateDiffTest-WindowsLineEndings.inc' . "\n";
$expected .= '+++ PHP_CodeSniffer' . "\n";
$expected .= '@@ -1,7 +1,7 @@' . "\n";
$expected .= '-<?php' . "\n";
$expected .= '-// Comment with 2 spaces trailing whitespace. ' . "\n";
$expected .= '-$var = FALSE;' . "\n";
$expected .= '-' . "\n";
$expected .= '-if ($var) {' . "\n";
$expected .= '- echo \'This line is tab indented\';' . "\n";
$expected .= '-}' . "\n";
$expected .= '+<?php' . "\n";
$expected .= '+// Comment with 2 spaces trailing whitespace. ' . "\n";
$expected .= '+$var = FALSE;' . "\n";
$expected .= '+' . "\n";
$expected .= '+if ($var) {' . "\n";
$expected .= '+ echo \'This line is tab indented\';' . "\n";
$expected .= '+}' . "\n";
$filePath = __DIR__ . '/Fixtures/GenerateDiffTest-WindowsLineEndings.inc';
$diff = self::$phpcsFile->fixer->generateDiff($filePath, \false);
// Allow for the tests to pass on Windows too.
$diff = \str_replace('--- tests\\Core\\Fixer/', '--- tests/Core/Fixer/', $diff);
// Normalize line endings of the diff.
$diff = \preg_replace('`\\R`', "\n", $diff);
$this->assertSame($expected, $diff);
}
//end testGenerateDiffDifferentLineEndings()
}
//end class

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ExplainCustomRulesetTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
<rule ref="PSR12.ControlStructures"/>
<rule ref="Squiz.Scope.MethodScope"/>
<rule ref="PSR1">
<exclude name="PSR1.Files.SideEffects"/>
</rule>
</ruleset>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ExplainSingleSniffTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
<rule ref="Squiz.Scope.MethodScope"/>
</ruleset>

View File

@@ -0,0 +1,218 @@
<?php
/**
* Tests to verify that the "explain" command functions as expected.
*
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
* @copyright 2023 Juliette Reinders Folmer. All rights reserved.
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\Core\Ruleset;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Ruleset;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Runner;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Tests\ConfigDouble;
use ps_metrics_module_v4_0_5\PHPUnit\Framework\TestCase;
/**
* Test the Ruleset::explain() function.
*
* @covers \PHP_CodeSniffer\Ruleset::explain
*/
final class ExplainTest extends TestCase
{
/**
* Test the output of the "explain" command.
*
* @return void
*/
public function testExplain()
{
// Set up the ruleset.
$config = new ConfigDouble(['--standard=PSR1', '-e']);
$ruleset = new Ruleset($config);
$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;
$this->expectOutputString($expected);
$ruleset->explain();
}
//end testExplain()
/**
* Test the output of the "explain" command is not influenced by a user set report width.
*
* @return void
*/
public function testExplainAlwaysDisplaysCompleteSniffName()
{
// Set up the ruleset.
$config = new ConfigDouble(['--standard=PSR1', '-e', '--report-width=30']);
$ruleset = new Ruleset($config);
$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;
$this->expectOutputString($expected);
$ruleset->explain();
}
//end testExplainAlwaysDisplaysCompleteSniffName()
/**
* Test the output of the "explain" command when a ruleset only contains a single sniff.
*
* This is mostly about making sure that the summary line uses the correct grammar.
*
* @return void
*/
public function testExplainSingleSniff()
{
// Set up the ruleset.
$standard = __DIR__ . '/ExplainSingleSniffTest.xml';
$config = new ConfigDouble(["--standard={$standard}", '-e']);
$ruleset = new Ruleset($config);
$expected = \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);
$ruleset->explain();
}
//end testExplainSingleSniff()
/**
* Test that "explain" works correctly with custom rulesets.
*
* Verifies that:
* - The "standard" name is taken from the custom ruleset.
* - Any and all sniff additions and exclusions in the ruleset are taken into account correctly.
* - That the displayed list will have both the standards as well as the sniff names
* ordered alphabetically.
*
* @return void
*/
public function testExplainCustomRuleset()
{
// Set up the ruleset.
$standard = __DIR__ . '/ExplainCustomRulesetTest.xml';
$config = new ConfigDouble(["--standard={$standard}", '-e']);
$ruleset = new Ruleset($config);
$expected = \PHP_EOL;
$expected .= 'The ExplainCustomRulesetTest standard contains 10 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 (2 sniffs)' . \PHP_EOL;
$expected .= '---------------' . \PHP_EOL;
$expected .= ' PSR1.Classes.ClassDeclaration' . \PHP_EOL;
$expected .= ' PSR1.Methods.CamelCapsMethodName' . \PHP_EOL . \PHP_EOL;
$expected .= 'PSR12 (2 sniffs)' . \PHP_EOL;
$expected .= '----------------' . \PHP_EOL;
$expected .= ' PSR12.ControlStructures.BooleanOperatorPlacement' . \PHP_EOL;
$expected .= ' PSR12.ControlStructures.ControlStructureSpacing' . \PHP_EOL . \PHP_EOL;
$expected .= 'Squiz (2 sniffs)' . \PHP_EOL;
$expected .= '----------------' . \PHP_EOL;
$expected .= ' Squiz.Classes.ValidClassName' . \PHP_EOL;
$expected .= ' Squiz.Scope.MethodScope' . \PHP_EOL;
$this->expectOutputString($expected);
$ruleset->explain();
}
//end testExplainCustomRuleset()
/**
* Test the output of the "explain" command for a standard containing both deprecated
* and non-deprecated sniffs.
*
* Tests that:
* - Deprecated sniffs are marked with an asterix in the list.
* - A footnote is displayed explaining the asterix.
* - And that the "standard uses # deprecated sniffs" listing is **not** displayed.
*
* @return void
*/
public function testExplainWithDeprecatedSniffs()
{
// Set up the ruleset.
$standard = __DIR__ . "/ShowSniffDeprecationsTest.xml";
$config = new ConfigDouble(["--standard={$standard}", '-e']);
$ruleset = new Ruleset($config);
$expected = \PHP_EOL;
$expected .= 'The SniffDeprecationTest standard contains 9 sniffs' . \PHP_EOL . \PHP_EOL;
$expected .= 'Fixtures (9 sniffs)' . \PHP_EOL;
$expected .= '-------------------' . \PHP_EOL;
$expected .= ' Fixtures.Deprecated.WithLongReplacement *' . \PHP_EOL;
$expected .= ' Fixtures.Deprecated.WithoutReplacement *' . \PHP_EOL;
$expected .= ' Fixtures.Deprecated.WithReplacement *' . \PHP_EOL;
$expected .= ' Fixtures.Deprecated.WithReplacementContainingLinuxNewlines *' . \PHP_EOL;
$expected .= ' Fixtures.Deprecated.WithReplacementContainingNewlines *' . \PHP_EOL;
$expected .= ' Fixtures.SetProperty.AllowedAsDeclared' . \PHP_EOL;
$expected .= ' Fixtures.SetProperty.AllowedViaMagicMethod' . \PHP_EOL;
$expected .= ' Fixtures.SetProperty.AllowedViaStdClass' . \PHP_EOL;
$expected .= ' Fixtures.SetProperty.NotAllowedViaAttribute' . \PHP_EOL . \PHP_EOL;
$expected .= '* Sniffs marked with an asterix are deprecated.' . \PHP_EOL;
$this->expectOutputString($expected);
$ruleset->explain();
}
//end testExplainWithDeprecatedSniffs()
/**
* Test that each standard passed on the command-line is explained separately.
*
* @covers \PHP_CodeSniffer\Runner::runPHPCS
*
* @return void
*/
public function testExplainWillExplainEachStandardSeparately()
{
$standard = __DIR__ . '/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();
$exitCode = $runner->runPHPCS();
}
//end testExplainWillExplainEachStandardSeparately()
}
//end class

View File

@@ -0,0 +1,35 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\Deprecated;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class WithLongReplacementSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return 'v3.8.0';
}
public function getRemovalVersion()
{
return 'v4.0.0';
}
public function getDeprecationMessage()
{
return 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed. Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget libero.';
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\Deprecated;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class WithReplacementContainingLinuxNewlinesSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return 'v3.8.0';
}
public function getRemovalVersion()
{
return 'v4.0.0';
}
public function getDeprecationMessage()
{
return "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" . "Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.\n" . "Fusce egestas congue massa semper cursus. Donec quis pretium tellus.\n" . "In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem.\n" . 'Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas.';
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\Deprecated;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class WithReplacementContainingNewlinesSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return 'v3.8.0';
}
public function getRemovalVersion()
{
return 'v4.0.0';
}
public function getDeprecationMessage()
{
return 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' . \PHP_EOL . 'Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.' . \PHP_EOL . 'Fusce egestas congue massa semper cursus. Donec quis pretium tellus.' . \PHP_EOL . 'In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem.' . \PHP_EOL . 'Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas';
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\Deprecated;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class WithReplacementSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return 'v3.8.0';
}
public function getRemovalVersion()
{
return 'v4.0.0';
}
public function getDeprecationMessage()
{
return 'Use the Stnd.Category.OtherSniff sniff instead.';
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\Deprecated;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class WithoutReplacementSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return 'v3.4.0';
}
public function getRemovalVersion()
{
return 'v4.0.0';
}
public function getDeprecationMessage()
{
return '';
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,35 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\DeprecatedInvalid;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class EmptyDeprecationVersionSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return '';
}
public function getRemovalVersion()
{
return 'dummy';
}
public function getDeprecationMessage()
{
return 'dummy';
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\DeprecatedInvalid;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class EmptyRemovalVersionSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return 'dummy';
}
public function getRemovalVersion()
{
return '';
}
public function getDeprecationMessage()
{
return 'dummy';
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\DeprecatedInvalid;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
use stdClass;
class InvalidDeprecationMessageSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return 'dummy';
}
public function getRemovalVersion()
{
return 'dummy';
}
public function getDeprecationMessage()
{
return new stdClass();
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\DeprecatedInvalid;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class InvalidDeprecationVersionSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return 3.8;
}
public function getRemovalVersion()
{
return 'dummy';
}
public function getDeprecationMessage()
{
return 'dummy';
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\DeprecatedInvalid;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\DeprecatedSniff;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class InvalidRemovalVersionSniff implements Sniff, DeprecatedSniff
{
public function getDeprecationVersion()
{
return 'dummy';
}
public function getRemovalVersion()
{
return ['4.0'];
}
public function getDeprecationMessage()
{
return 'dummy';
}
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,24 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SetSniffPropertyTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\SetProperty;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class AllowedAsDeclaredSniff implements Sniff
{
public $arbitrarystring;
public $arbitraryarray;
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SetSniffPropertyTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\SetProperty;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
class AllowedViaMagicMethodSniff implements Sniff
{
private $magic = [];
public function __set($name, $value)
{
$this->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.
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SetSniffPropertyTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\SetProperty;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
use stdClass;
class AllowedViaStdClassSniff extends stdClass implements Sniff
{
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* Test fixture.
*
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\SetSniffPropertyTest
*/
namespace ps_metrics_module_v4_0_5\Fixtures\Sniffs\SetProperty;
use AllowDynamicProperties;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Files\File;
use ps_metrics_module_v4_0_5\PHP_CodeSniffer\Sniffs\Sniff;
#[AllowDynamicProperties]
class NotAllowedViaAttributeSniff implements Sniff
{
public function register()
{
return [\T_WHITESPACE];
}
public function process(File $phpcsFile, $stackPtr)
{
// Do something.
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

Some files were not shown because too many files have changed in this diff Show More