mirror of
https://gitlab.com/signalytic/client-external/streamline/streamline-emr.git
synced 2026-09-13 11:41:31 +00:00
resolved conflicts
This commit is contained in:
+212
@@ -0,0 +1,212 @@
|
||||
<?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 PHP_CodeSniffer\Tests;
|
||||
|
||||
use 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()
|
||||
|
||||
|
||||
/**
|
||||
* Ensures the static properties in the Config class are reset to their default values
|
||||
* when the ConfigDouble is no longer used.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->setStaticConfigProperty('overriddenDefaults', []);
|
||||
$this->setStaticConfigProperty('executablePaths', []);
|
||||
$this->setStaticConfigProperty('configData', null);
|
||||
$this->setStaticConfigProperty('configDataFile', null);
|
||||
|
||||
}//end __destruct()
|
||||
|
||||
|
||||
/**
|
||||
* 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('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('PHP_CodeSniffer\Config', $name);
|
||||
$property->setAccessible(true);
|
||||
$property->setValue(null, $value);
|
||||
$property->setAccessible(false);
|
||||
|
||||
}//end setStaticConfigProperty()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+223
@@ -0,0 +1,223 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core;
|
||||
|
||||
use Exception;
|
||||
use PHP_CodeSniffer\Files\DummyFile;
|
||||
use PHP_CodeSniffer\Files\File;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Tests\ConfigDouble;
|
||||
use 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()
|
||||
|
||||
|
||||
/**
|
||||
* Clean up after finished test by resetting all static properties on the class to their default values.
|
||||
*
|
||||
* Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::tearDownAfterClass()}
|
||||
* method.
|
||||
*
|
||||
* @afterClass
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function reset()
|
||||
{
|
||||
// Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics.
|
||||
// The explicit method call prevents potential stray test-local references to the $config object
|
||||
// preventing the destructor from running the clean up (which without stray references would be
|
||||
// automagically triggered when `self::$phpcsFile` is reset, but we can't definitively rely on that).
|
||||
if (isset(self::$phpcsFile) === true) {
|
||||
self::$phpcsFile->config->__destruct();
|
||||
}
|
||||
|
||||
self::$fileExtension = 'inc';
|
||||
self::$tabWidth = 4;
|
||||
self::$phpcsFile = null;
|
||||
|
||||
}//end reset()
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @throws Exception When the test delimiter comment is not found.
|
||||
* @throws Exception When the test target token is not found.
|
||||
*/
|
||||
public static function getTargetTokenFromFile(File $phpcsFile, $commentString, $tokenType, $tokenContent=null)
|
||||
{
|
||||
$start = ($phpcsFile->numTokens - 1);
|
||||
$comment = $phpcsFile->findPrevious(
|
||||
T_COMMENT,
|
||||
$start,
|
||||
null,
|
||||
false,
|
||||
$commentString
|
||||
);
|
||||
|
||||
if ($comment === false) {
|
||||
throw new Exception(
|
||||
sprintf('Failed to find the test marker: %s in test case file %s', $commentString, $phpcsFile->getFilename())
|
||||
);
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
throw new Exception($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 = '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
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core;
|
||||
|
||||
use PHP_CodeSniffer\Tests\FileList;
|
||||
use PHPUnit\Framework\TestSuite;
|
||||
use 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
|
||||
Vendored
+332
@@ -0,0 +1,332 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core\Config;
|
||||
|
||||
use PHP_CodeSniffer\Config;
|
||||
use 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.50,
|
||||
'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('PHP_CodeSniffer\Config', $name);
|
||||
$property->setAccessible(true);
|
||||
$property->setValue(null, $value);
|
||||
$property->setAccessible(false);
|
||||
|
||||
}//end setStaticProperty()
|
||||
|
||||
|
||||
}//end class
|
||||
+1278
File diff suppressed because it is too large
Load Diff
Vendored
+457
@@ -0,0 +1,457 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File::findEndOfStatement method.
|
||||
*
|
||||
* @covers \PHP_CodeSniffer\Files\File::findEndOfStatement
|
||||
*/
|
||||
final class FindEndOfStatementTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that end of statement is NEVER before the "current" token.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEndIsNeverLessThanCurrentToken()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$errors = [];
|
||||
|
||||
for ($i = 0; $i < self::$phpcsFile->numTokens; $i++) {
|
||||
if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$end = self::$phpcsFile->findEndOfStatement($i);
|
||||
|
||||
// Collect all the errors.
|
||||
if ($end < $i) {
|
||||
$errors[] = sprintf(
|
||||
'End of statement for token %1$d (%2$s: %3$s) on line %4$d is %5$d (%6$s), which is less than %1$d',
|
||||
$i,
|
||||
$tokens[$i]['type'],
|
||||
$tokens[$i]['content'],
|
||||
$tokens[$i]['line'],
|
||||
$end,
|
||||
$tokens[$end]['type']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertSame([], $errors);
|
||||
|
||||
}//end testEndIsNeverLessThanCurrentToken()
|
||||
|
||||
|
||||
/**
|
||||
* Test a simple assignment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSimpleAssignment()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testSimpleAssignment */', T_VARIABLE);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 5), $found);
|
||||
|
||||
}//end testSimpleAssignment()
|
||||
|
||||
|
||||
/**
|
||||
* Test a direct call to a control structure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testControlStructure()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testControlStructure */', T_WHILE);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 6), $found);
|
||||
|
||||
}//end testControlStructure()
|
||||
|
||||
|
||||
/**
|
||||
* Test the assignment of a closure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testClosureAssignment()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testClosureAssignment */', T_VARIABLE, '$a');
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 13), $found);
|
||||
|
||||
}//end testClosureAssignment()
|
||||
|
||||
|
||||
/**
|
||||
* Test using a heredoc in a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredocFunctionArg()
|
||||
{
|
||||
// Find the end of the function.
|
||||
$start = $this->getTargetToken('/* testHeredocFunctionArg */', T_STRING, 'myFunction');
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 10), $found);
|
||||
|
||||
// Find the end of the heredoc.
|
||||
$start += 2;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 4), $found);
|
||||
|
||||
// Find the end of the last arg.
|
||||
$start = ($found + 2);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testHeredocFunctionArg()
|
||||
|
||||
|
||||
/**
|
||||
* Test parts of a switch statement.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSwitch()
|
||||
{
|
||||
// Find the end of the switch.
|
||||
$start = $this->getTargetToken('/* testSwitch */', T_SWITCH);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 28), $found);
|
||||
|
||||
// Find the end of the case.
|
||||
$start += 9;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 8), $found);
|
||||
|
||||
// Find the end of default case.
|
||||
$start += 11;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 6), $found);
|
||||
|
||||
}//end testSwitch()
|
||||
|
||||
|
||||
/**
|
||||
* Test statements that are array values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStatementAsArrayValue()
|
||||
{
|
||||
// Test short array syntax.
|
||||
$start = $this->getTargetToken('/* testStatementAsArrayValue */', T_NEW);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 2), $found);
|
||||
|
||||
// Test long array syntax.
|
||||
$start += 12;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 2), $found);
|
||||
|
||||
// Test same statement outside of array.
|
||||
$start += 10;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 3), $found);
|
||||
|
||||
}//end testStatementAsArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test a use group.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUseGroup()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testUseGroup */', T_USE);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 23), $found);
|
||||
|
||||
}//end testUseGroup()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function as array value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionArrayValue()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_FN);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 9), $found);
|
||||
|
||||
}//end testArrowFunctionArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test static arrow function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStaticArrowFunction()
|
||||
{
|
||||
$static = $this->getTargetToken('/* testStaticArrowFunction */', T_STATIC);
|
||||
$fn = $this->getTargetToken('/* testStaticArrowFunction */', T_FN);
|
||||
|
||||
$endOfStatementStatic = self::$phpcsFile->findEndOfStatement($static);
|
||||
$endOfStatementFn = self::$phpcsFile->findEndOfStatement($fn);
|
||||
|
||||
$this->assertSame($endOfStatementFn, $endOfStatementStatic);
|
||||
|
||||
}//end testStaticArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with return value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionReturnValue()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionReturnValue */', T_FN);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 18), $found);
|
||||
|
||||
}//end testArrowFunctionReturnValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function used as a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionAsArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionAsArgument */', T_FN);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 8), $found);
|
||||
|
||||
}//end testArrowFunctionAsArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with arrays used as a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionWithArrayAsArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionWithArrayAsArgument */', T_FN);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 17), $found);
|
||||
|
||||
}//end testArrowFunctionWithArrayAsArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test simple match expression case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchCase()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchCase */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 5), $found);
|
||||
|
||||
$start = $this->getTargetToken('/* testMatchCase */', T_CONSTANT_ENCAPSED_STRING);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 1), $found);
|
||||
|
||||
}//end testMatchCase()
|
||||
|
||||
|
||||
/**
|
||||
* Test simple match expression default case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchDefault()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchDefault */', T_MATCH_DEFAULT);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 4), $found);
|
||||
|
||||
$start = $this->getTargetToken('/* testMatchDefault */', T_CONSTANT_ENCAPSED_STRING);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testMatchDefault()
|
||||
|
||||
|
||||
/**
|
||||
* Test multiple comma-separated match expression case values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchMultipleCase()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchMultipleCase */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
$this->assertSame(($start + 13), $found);
|
||||
|
||||
$start += 6;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
$this->assertSame(($start + 7), $found);
|
||||
|
||||
}//end testMatchMultipleCase()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression default case with trailing comma.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchDefaultComma()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchDefaultComma */', T_MATCH_DEFAULT);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 5), $found);
|
||||
|
||||
}//end testMatchDefaultComma()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with function call.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchFunctionCall()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchFunctionCall */', T_STRING);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 12), $found);
|
||||
|
||||
$start += 8;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 1), $found);
|
||||
|
||||
}//end testMatchFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with function call in the arm.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchFunctionCallArm()
|
||||
{
|
||||
// Check the first case.
|
||||
$start = $this->getTargetToken('/* testMatchFunctionCallArm */', T_STRING);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 21), $found);
|
||||
|
||||
// Check the second case.
|
||||
$start += 24;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 21), $found);
|
||||
|
||||
}//end testMatchFunctionCallArm()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with closure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchClosure()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchClosure */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 14), $found);
|
||||
|
||||
$start += 17;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 14), $found);
|
||||
|
||||
}//end testMatchClosure()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with array declaration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchArray()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchArray */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 11), $found);
|
||||
|
||||
$start += 14;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 22), $found);
|
||||
|
||||
}//end testMatchArray()
|
||||
|
||||
|
||||
/**
|
||||
* Test nested match expressions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedMatch()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testNestedMatch */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 30), $found);
|
||||
|
||||
$start += 21;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 5), $found);
|
||||
|
||||
}//end testNestedMatch()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+200
@@ -0,0 +1,200 @@
|
||||
<?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() => 1,
|
||||
'b' => fn() => 1,
|
||||
];
|
||||
|
||||
/* testStaticArrowFunction */
|
||||
static fn ($a) => $a;
|
||||
|
||||
/* testArrowFunctionReturnValue */
|
||||
fn(): array => [a($a, $b)];
|
||||
|
||||
/* testArrowFunctionAsArgument */
|
||||
$foo = foo(
|
||||
fn() => bar()
|
||||
);
|
||||
|
||||
/* testArrowFunctionWithArrayAsArgument */
|
||||
$foo = foo(
|
||||
fn() => [$row[0], $row[3]]
|
||||
);
|
||||
|
||||
$match = match ($a) {
|
||||
/* testMatchCase */
|
||||
1 => 'foo',
|
||||
/* testMatchDefault */
|
||||
default => 'bar'
|
||||
};
|
||||
|
||||
$match = match ($a) {
|
||||
/* testMatchMultipleCase */
|
||||
1, 2, => $a * $b,
|
||||
/* testMatchDefaultComma */
|
||||
default, => 'something'
|
||||
};
|
||||
|
||||
match ($pressedKey) {
|
||||
/* testMatchFunctionCall */
|
||||
Key::RETURN_ => save($value, $user)
|
||||
};
|
||||
|
||||
$result = match (true) {
|
||||
/* testMatchFunctionCallArm */
|
||||
str_contains($text, 'Welcome') || str_contains($text, 'Hello') => 'en',
|
||||
str_contains($text, 'Bienvenue') || str_contains($text, 'Bonjour') => 'fr',
|
||||
default => 'pl'
|
||||
};
|
||||
|
||||
/* testMatchClosure */
|
||||
$result = match ($key) {
|
||||
1 => function($a, $b) {},
|
||||
2 => function($b, $c) {},
|
||||
};
|
||||
|
||||
/* testMatchArray */
|
||||
$result = match ($key) {
|
||||
1 => [1,2,3],
|
||||
2 => [1 => one($a, $b), 2 => two($b, $c)],
|
||||
3 => [],
|
||||
};
|
||||
|
||||
/* testNestedMatch */
|
||||
$result = match ($key) {
|
||||
1 => match ($key) {
|
||||
1 => 'one',
|
||||
2 => 'two',
|
||||
},
|
||||
2 => match ($key) {
|
||||
1 => 'two',
|
||||
2 => 'one',
|
||||
},
|
||||
};
|
||||
|
||||
return 0;
|
||||
|
||||
/* testOpenTag */
|
||||
?>
|
||||
<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 1;
|
||||
|
||||
case 2:
|
||||
/* testInsideCaseContinueStatement */
|
||||
continue 1;
|
||||
|
||||
case 3:
|
||||
/* testInsideCaseReturnStatement */
|
||||
return false;
|
||||
|
||||
case 4:
|
||||
/* testInsideCaseExitStatement */
|
||||
exit(1);
|
||||
|
||||
case 5:
|
||||
/* testInsideCaseThrowStatement */
|
||||
throw new Exception();
|
||||
|
||||
/* testDefaultStatement */
|
||||
default:
|
||||
/* testInsideDefaultContinueStatement */
|
||||
continue $var;
|
||||
}
|
||||
|
||||
match ($var) {
|
||||
true =>
|
||||
/* test437ClosureDeclaration */
|
||||
function ($var) {
|
||||
/* test437EchoNestedWithinClosureWithinMatch */
|
||||
echo $var, 'text', PHP_EOL;
|
||||
},
|
||||
default => false
|
||||
};
|
||||
|
||||
match ($var) {
|
||||
/* test437NestedLongArrayWithinMatch */
|
||||
'a' => array( 1, 2.5, $var),
|
||||
/* test437NestedFunctionCallWithinMatch */
|
||||
'b' => functionCall( 11, $var, 50.50),
|
||||
/* test437NestedArrowFunctionWithinMatch */
|
||||
'c' => fn($p1, /* test437FnSecondParamWithinMatch */ $p2) => $p1 + $p2,
|
||||
default => false
|
||||
};
|
||||
|
||||
callMe($paramA, match ($var) {
|
||||
/* test437NestedLongArrayWithinNestedMatch */
|
||||
'a' => array( 1, 2.5, $var),
|
||||
/* test437NestedFunctionCallWithinNestedMatch */
|
||||
'b' => functionCall( 11, $var, 50.50),
|
||||
/* test437NestedArrowFunctionWithinNestedMatch */
|
||||
'c' => fn($p1, /* test437FnSecondParamWithinNestedMatch */ $p2) => $p1 + $p2,
|
||||
default => false
|
||||
});
|
||||
|
||||
match ($var) {
|
||||
/* test437NestedShortArrayWithinMatch */
|
||||
'a' => [ 1, 2.5, $var],
|
||||
default => false
|
||||
};
|
||||
Vendored
+973
@@ -0,0 +1,973 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File:findStartOfStatement method.
|
||||
*
|
||||
* @covers \PHP_CodeSniffer\Files\File::findStartOfStatement
|
||||
*/
|
||||
final class FindStartOfStatementTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that start of statement is NEVER beyond the "current" token.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStartIsNeverMoreThanCurrentToken()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$errors = [];
|
||||
|
||||
for ($i = 0; $i < self::$phpcsFile->numTokens; $i++) {
|
||||
if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$start = self::$phpcsFile->findStartOfStatement($i);
|
||||
|
||||
// Collect all the errors.
|
||||
if ($start > $i) {
|
||||
$errors[] = sprintf(
|
||||
'Start of statement for token %1$d (%2$s: %3$s) on line %4$d is %5$d (%6$s), which is more than %1$d',
|
||||
$i,
|
||||
$tokens[$i]['type'],
|
||||
$tokens[$i]['content'],
|
||||
$tokens[$i]['line'],
|
||||
$start,
|
||||
$tokens[$start]['type']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertSame([], $errors);
|
||||
|
||||
}//end testStartIsNeverMoreThanCurrentToken()
|
||||
|
||||
|
||||
/**
|
||||
* Test a simple assignment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSimpleAssignment()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testSimpleAssignment */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 5), $found);
|
||||
|
||||
}//end testSimpleAssignment()
|
||||
|
||||
|
||||
/**
|
||||
* Test a function call.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFunctionCall()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testFunctionCall */', T_CLOSE_PARENTHESIS);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
}//end testFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test a function call.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFunctionCallArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testFunctionCallArgument */', T_VARIABLE, '$b');
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testFunctionCallArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test a direct call to a control structure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testControlStructure()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testControlStructure */', T_CLOSE_CURLY_BRACKET);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
}//end testControlStructure()
|
||||
|
||||
|
||||
/**
|
||||
* Test the assignment of a closure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testClosureAssignment()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testClosureAssignment */', T_CLOSE_CURLY_BRACKET);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 11), $found);
|
||||
|
||||
}//end testClosureAssignment()
|
||||
|
||||
|
||||
/**
|
||||
* Test using a heredoc in a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredocFunctionArg()
|
||||
{
|
||||
// Find the start of the function.
|
||||
$start = $this->getTargetToken('/* testHeredocFunctionArg */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 10), $found);
|
||||
|
||||
// Find the start of the heredoc.
|
||||
$start -= 4;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 4), $found);
|
||||
|
||||
// Find the start of the last arg.
|
||||
$start += 2;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testHeredocFunctionArg()
|
||||
|
||||
|
||||
/**
|
||||
* Test parts of a switch statement.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSwitch()
|
||||
{
|
||||
// Find the start of the switch.
|
||||
$start = $this->getTargetToken('/* testSwitch */', T_CLOSE_CURLY_BRACKET);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 47), $found);
|
||||
|
||||
// Find the start of default case.
|
||||
$start -= 5;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
// Find the start of the second case.
|
||||
$start -= 12;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 5), $found);
|
||||
|
||||
// Find the start of the first case.
|
||||
$start -= 13;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 8), $found);
|
||||
|
||||
// Test inside the first case.
|
||||
$start--;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
}//end testSwitch()
|
||||
|
||||
|
||||
/**
|
||||
* Test statements that are array values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStatementAsArrayValue()
|
||||
{
|
||||
// Test short array syntax.
|
||||
$start = $this->getTargetToken('/* testStatementAsArrayValue */', T_STRING, 'Datetime');
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 2), $found);
|
||||
|
||||
// Test long array syntax.
|
||||
$start += 12;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 2), $found);
|
||||
|
||||
// Test same statement outside of array.
|
||||
$start++;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 9), $found);
|
||||
|
||||
// Test with an array index.
|
||||
$start += 17;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 5), $found);
|
||||
|
||||
}//end testStatementAsArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test a use group.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUseGroup()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testUseGroup */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 23), $found);
|
||||
|
||||
}//end testUseGroup()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function as array value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionArrayValue()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_COMMA);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 7), $found);
|
||||
|
||||
}//end testArrowFunctionArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test static arrow function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStaticArrowFunction()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testStaticArrowFunction */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 11), $found);
|
||||
|
||||
}//end testStaticArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with return value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionReturnValue()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionReturnValue */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 18), $found);
|
||||
|
||||
}//end testArrowFunctionReturnValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function used as a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionAsArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionAsArgument */', T_FN);
|
||||
$start += 8;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 8), $found);
|
||||
|
||||
}//end testArrowFunctionAsArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with arrays used as a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionWithArrayAsArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionWithArrayAsArgument */', T_FN);
|
||||
$start += 17;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 17), $found);
|
||||
|
||||
}//end testArrowFunctionWithArrayAsArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test simple match expression case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchCase()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchCase */', T_COMMA);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
}//end testMatchCase()
|
||||
|
||||
|
||||
/**
|
||||
* Test simple match expression default case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchDefault()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchDefault */', T_CONSTANT_ENCAPSED_STRING, "'bar'");
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testMatchDefault()
|
||||
|
||||
|
||||
/**
|
||||
* Test multiple comma-separated match expression case values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchMultipleCase()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchMultipleCase */', T_MATCH_ARROW);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
$start += 6;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 4), $found);
|
||||
|
||||
}//end testMatchMultipleCase()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression default case with trailing comma.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchDefaultComma()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchDefaultComma */', T_MATCH_ARROW);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 3), $found);
|
||||
|
||||
$start += 2;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testMatchDefaultComma()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with function call.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchFunctionCall()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchFunctionCall */', T_CLOSE_PARENTHESIS);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
}//end testMatchFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with function call in the arm.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchFunctionCallArm()
|
||||
{
|
||||
// Check the first case.
|
||||
$start = $this->getTargetToken('/* testMatchFunctionCallArm */', T_MATCH_ARROW);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 18), $found);
|
||||
|
||||
// Check the second case.
|
||||
$start += 24;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 18), $found);
|
||||
|
||||
}//end testMatchFunctionCallArm()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with closure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchClosure()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchClosure */', T_LNUMBER);
|
||||
$start += 14;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 10), $found);
|
||||
|
||||
$start += 17;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 10), $found);
|
||||
|
||||
}//end testMatchClosure()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with array declaration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchArray()
|
||||
{
|
||||
// Start of first case statement.
|
||||
$start = $this->getTargetToken('/* testMatchArray */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
// Comma after first statement.
|
||||
$start += 11;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
$this->assertSame(($start - 7), $found);
|
||||
|
||||
// Start of second case statement.
|
||||
$start += 3;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
// Comma after first statement.
|
||||
$start += 30;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
$this->assertSame(($start - 26), $found);
|
||||
|
||||
}//end testMatchArray()
|
||||
|
||||
|
||||
/**
|
||||
* Test nested match expressions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedMatch()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testNestedMatch */', T_LNUMBER);
|
||||
$start += 30;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 26), $found);
|
||||
|
||||
$start -= 4;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
$start -= 3;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 2), $found);
|
||||
|
||||
}//end testNestedMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Test PHP open tag.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testOpenTag()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testOpenTag */', T_OPEN_TAG);
|
||||
$start += 2;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
}//end testOpenTag()
|
||||
|
||||
|
||||
/**
|
||||
* Test PHP short open echo tag.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testOpenTagWithEcho()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testOpenTagWithEcho */', T_OPEN_TAG_WITH_ECHO);
|
||||
$start += 3;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
}//end testOpenTagWithEcho()
|
||||
|
||||
|
||||
/**
|
||||
* Test object call on result of static function call with arrow function as parameter and wrapped within an array.
|
||||
*
|
||||
* @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2849
|
||||
* @link https://github.com/squizlabs/PHP_CodeSniffer/commit/fbf67efc3fc0c2a355f5585d49f4f6fe160ff2f9
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testObjectCallPrecededByArrowFunctionAsFunctionCallParameterInArray()
|
||||
{
|
||||
$expected = $this->getTargetToken('/* testPrecededByArrowFunctionInArray - Expected */', T_STRING, 'Url');
|
||||
|
||||
$start = $this->getTargetToken('/* testPrecededByArrowFunctionInArray */', T_STRING, 'onlyOnDetail');
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame($expected, $found);
|
||||
|
||||
}//end testObjectCallPrecededByArrowFunctionAsFunctionCallParameterInArray()
|
||||
|
||||
|
||||
/**
|
||||
* Test finding the start of a statement inside a switch control structure case/default statement.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param int|string $targets The token to search for after the test marker.
|
||||
* @param string|int $expectedTarget Token code of the expected start of statement stack pointer.
|
||||
*
|
||||
* @link https://github.com/squizlabs/php_codesniffer/issues/3192
|
||||
* @link https://github.com/squizlabs/PHP_CodeSniffer/pull/3186/commits/18a0e54735bb9b3850fec266e5f4c50dacf618ea
|
||||
*
|
||||
* @dataProvider dataFindStartInsideSwitchCaseDefaultStatements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFindStartInsideSwitchCaseDefaultStatements($testMarker, $targets, $expectedTarget)
|
||||
{
|
||||
$testToken = $this->getTargetToken($testMarker, $targets);
|
||||
$expected = $this->getTargetToken($testMarker, $expectedTarget);
|
||||
|
||||
$found = self::$phpcsFile->findStartOfStatement($testToken);
|
||||
|
||||
$this->assertSame($expected, $found);
|
||||
|
||||
}//end testFindStartInsideSwitchCaseDefaultStatements()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array<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()
|
||||
|
||||
|
||||
/**
|
||||
* Test finding the start of a statement inside a closed scope nested within a match expressions.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param int|string $target The token to search for after the test marker.
|
||||
* @param int|string $expectedTarget Token code of the expected start of statement stack pointer.
|
||||
*
|
||||
* @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437
|
||||
*
|
||||
* @dataProvider dataFindStartInsideClosedScopeNestedWithinMatch
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFindStartInsideClosedScopeNestedWithinMatch($testMarker, $target, $expectedTarget)
|
||||
{
|
||||
$testToken = $this->getTargetToken($testMarker, $target);
|
||||
$expected = $this->getTargetToken($testMarker, $expectedTarget);
|
||||
|
||||
$found = self::$phpcsFile->findStartOfStatement($testToken);
|
||||
|
||||
$this->assertSame($expected, $found);
|
||||
|
||||
}//end testFindStartInsideClosedScopeNestedWithinMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array<string, array<string, int|string>>
|
||||
*/
|
||||
public static function dataFindStartInsideClosedScopeNestedWithinMatch()
|
||||
{
|
||||
return [
|
||||
// These were already working correctly.
|
||||
'Closure function keyword should be start of closure - closure keyword' => [
|
||||
'testMarker' => '/* test437ClosureDeclaration */',
|
||||
'target' => T_CLOSURE,
|
||||
'expectedTarget' => T_CLOSURE,
|
||||
],
|
||||
'Open curly is a statement/expression opener - open curly' => [
|
||||
'testMarker' => '/* test437ClosureDeclaration */',
|
||||
'target' => T_OPEN_CURLY_BRACKET,
|
||||
'expectedTarget' => T_OPEN_CURLY_BRACKET,
|
||||
],
|
||||
|
||||
'Echo should be start for expression - echo keyword' => [
|
||||
'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */',
|
||||
'target' => T_ECHO,
|
||||
'expectedTarget' => T_ECHO,
|
||||
],
|
||||
'Echo should be start for expression - variable' => [
|
||||
'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_ECHO,
|
||||
],
|
||||
'Echo should be start for expression - comma' => [
|
||||
'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */',
|
||||
'target' => T_COMMA,
|
||||
'expectedTarget' => T_ECHO,
|
||||
],
|
||||
|
||||
// These were not working correctly and would previously return the close curly of the match expression.
|
||||
'First token after comma in echo expression should be start for expression - text string' => [
|
||||
'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */',
|
||||
'target' => T_CONSTANT_ENCAPSED_STRING,
|
||||
'expectedTarget' => T_CONSTANT_ENCAPSED_STRING,
|
||||
],
|
||||
'First token after comma in echo expression - PHP_EOL constant' => [
|
||||
'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */',
|
||||
'target' => T_STRING,
|
||||
'expectedTarget' => T_STRING,
|
||||
],
|
||||
'First token after comma in echo expression - semicolon' => [
|
||||
'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */',
|
||||
'target' => T_SEMICOLON,
|
||||
'expectedTarget' => T_STRING,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataFindStartInsideClosedScopeNestedWithinMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Test finding the start of a statement for a token within a set of parentheses within a match expressions.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param int|string $target The token to search for after the test marker.
|
||||
* @param int|string $expectedTarget Token code of the expected start of statement stack pointer.
|
||||
*
|
||||
* @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437
|
||||
*
|
||||
* @dataProvider dataFindStartInsideParenthesesNestedWithinMatch
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFindStartInsideParenthesesNestedWithinMatch($testMarker, $target, $expectedTarget)
|
||||
{
|
||||
$testToken = $this->getTargetToken($testMarker, $target);
|
||||
$expected = $this->getTargetToken($testMarker, $expectedTarget);
|
||||
|
||||
$found = self::$phpcsFile->findStartOfStatement($testToken);
|
||||
|
||||
$this->assertSame($expected, $found);
|
||||
|
||||
}//end testFindStartInsideParenthesesNestedWithinMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array<string, array<string, int|string>>
|
||||
*/
|
||||
public static function dataFindStartInsideParenthesesNestedWithinMatch()
|
||||
{
|
||||
return [
|
||||
'Array item itself should be start for first array item' => [
|
||||
'testMarker' => '/* test437NestedLongArrayWithinMatch */',
|
||||
'target' => T_LNUMBER,
|
||||
'expectedTarget' => T_LNUMBER,
|
||||
],
|
||||
'Array item itself should be start for second array item' => [
|
||||
'testMarker' => '/* test437NestedLongArrayWithinMatch */',
|
||||
'target' => T_DNUMBER,
|
||||
'expectedTarget' => T_DNUMBER,
|
||||
],
|
||||
'Array item itself should be start for third array item' => [
|
||||
'testMarker' => '/* test437NestedLongArrayWithinMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_VARIABLE,
|
||||
],
|
||||
|
||||
'Parameter itself should be start for first param passed to function call' => [
|
||||
'testMarker' => '/* test437NestedFunctionCallWithinMatch */',
|
||||
'target' => T_LNUMBER,
|
||||
'expectedTarget' => T_LNUMBER,
|
||||
],
|
||||
'Parameter itself should be start for second param passed to function call' => [
|
||||
'testMarker' => '/* test437NestedFunctionCallWithinMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_VARIABLE,
|
||||
],
|
||||
'Parameter itself should be start for third param passed to function call' => [
|
||||
'testMarker' => '/* test437NestedFunctionCallWithinMatch */',
|
||||
'target' => T_DNUMBER,
|
||||
'expectedTarget' => T_DNUMBER,
|
||||
],
|
||||
|
||||
'Parameter itself should be start for first param declared in arrow function' => [
|
||||
'testMarker' => '/* test437NestedArrowFunctionWithinMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_VARIABLE,
|
||||
],
|
||||
'Parameter itself should be start for second param declared in arrow function' => [
|
||||
'testMarker' => '/* test437FnSecondParamWithinMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_VARIABLE,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataFindStartInsideParenthesesNestedWithinMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Test finding the start of a statement for a token within a set of parentheses within a match expressions,
|
||||
* which itself is nested within parentheses.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param int|string $target The token to search for after the test marker.
|
||||
* @param int|string $expectedTarget Token code of the expected start of statement stack pointer.
|
||||
*
|
||||
* @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437
|
||||
*
|
||||
* @dataProvider dataFindStartInsideParenthesesNestedWithinNestedMatch
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFindStartInsideParenthesesNestedWithinNestedMatch($testMarker, $target, $expectedTarget)
|
||||
{
|
||||
$testToken = $this->getTargetToken($testMarker, $target);
|
||||
$expected = $this->getTargetToken($testMarker, $expectedTarget);
|
||||
|
||||
$found = self::$phpcsFile->findStartOfStatement($testToken);
|
||||
|
||||
$this->assertSame($expected, $found);
|
||||
|
||||
}//end testFindStartInsideParenthesesNestedWithinNestedMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array<string, array<string, int|string>>
|
||||
*/
|
||||
public static function dataFindStartInsideParenthesesNestedWithinNestedMatch()
|
||||
{
|
||||
return [
|
||||
'Array item itself should be start for first array item' => [
|
||||
'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */',
|
||||
'target' => T_LNUMBER,
|
||||
'expectedTarget' => T_LNUMBER,
|
||||
],
|
||||
'Array item itself should be start for second array item' => [
|
||||
'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */',
|
||||
'target' => T_DNUMBER,
|
||||
'expectedTarget' => T_DNUMBER,
|
||||
],
|
||||
'Array item itself should be start for third array item' => [
|
||||
'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_VARIABLE,
|
||||
],
|
||||
|
||||
'Parameter itself should be start for first param passed to function call' => [
|
||||
'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */',
|
||||
'target' => T_LNUMBER,
|
||||
'expectedTarget' => T_LNUMBER,
|
||||
],
|
||||
'Parameter itself should be start for second param passed to function call' => [
|
||||
'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_VARIABLE,
|
||||
],
|
||||
'Parameter itself should be start for third param passed to function call' => [
|
||||
'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */',
|
||||
'target' => T_DNUMBER,
|
||||
'expectedTarget' => T_DNUMBER,
|
||||
],
|
||||
|
||||
'Parameter itself should be start for first param declared in arrow function' => [
|
||||
'testMarker' => '/* test437NestedArrowFunctionWithinNestedMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_VARIABLE,
|
||||
],
|
||||
'Parameter itself should be start for second param declared in arrow function' => [
|
||||
'testMarker' => '/* test437FnSecondParamWithinNestedMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_VARIABLE,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataFindStartInsideParenthesesNestedWithinNestedMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Test finding the start of a statement for a token within a short array within a match expressions.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param int|string $target The token to search for after the test marker.
|
||||
* @param int|string $expectedTarget Token code of the expected start of statement stack pointer.
|
||||
*
|
||||
* @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437
|
||||
*
|
||||
* @dataProvider dataFindStartInsideShortArrayNestedWithinMatch
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFindStartInsideShortArrayNestedWithinMatch($testMarker, $target, $expectedTarget)
|
||||
{
|
||||
$testToken = $this->getTargetToken($testMarker, $target);
|
||||
$expected = $this->getTargetToken($testMarker, $expectedTarget);
|
||||
|
||||
$found = self::$phpcsFile->findStartOfStatement($testToken);
|
||||
|
||||
$this->assertSame($expected, $found);
|
||||
|
||||
}//end testFindStartInsideShortArrayNestedWithinMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array<string, array<string, int|string>>
|
||||
*/
|
||||
public static function dataFindStartInsideShortArrayNestedWithinMatch()
|
||||
{
|
||||
return [
|
||||
'Array item itself should be start for first array item' => [
|
||||
'testMarker' => '/* test437NestedShortArrayWithinMatch */',
|
||||
'target' => T_LNUMBER,
|
||||
'expectedTarget' => T_LNUMBER,
|
||||
],
|
||||
'Array item itself should be start for second array item' => [
|
||||
'testMarker' => '/* test437NestedShortArrayWithinMatch */',
|
||||
'target' => T_DNUMBER,
|
||||
'expectedTarget' => T_DNUMBER,
|
||||
],
|
||||
'Array item itself should be start for third array item' => [
|
||||
'testMarker' => '/* test437NestedShortArrayWithinMatch */',
|
||||
'target' => T_VARIABLE,
|
||||
'expectedTarget' => T_VARIABLE,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataFindStartInsideShortArrayNestedWithinMatch()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+356
@@ -0,0 +1,356 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
trait DNFTypes {
|
||||
/* testPHP82DNFTypeStatic */
|
||||
public static (Foo&\Bar)|bool $propA;
|
||||
|
||||
/* testPHP82DNFTypeReadonlyA */
|
||||
protected readonly float|(Partially\Qualified&Traversable) $propB;
|
||||
|
||||
/* testPHP82DNFTypeReadonlyB */
|
||||
private readonly (namespace\Foo&Bar)|string $propC;
|
||||
|
||||
/* testPHP82DNFTypeIllegalNullable */
|
||||
// Intentional fatal error - nullable operator cannot be combined with DNF.
|
||||
var ?(A&\Pck\B)|bool $propD;
|
||||
}
|
||||
Vendored
+1191
File diff suppressed because it is too large
Load Diff
Vendored
+338
@@ -0,0 +1,338 @@
|
||||
<?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'),
|
||||
) {}
|
||||
|
||||
/* testPHP82DNFTypes */
|
||||
function dnfTypes(
|
||||
#[MyAttribute]
|
||||
false|(Foo&Bar)|true $obj1,
|
||||
(\Boo&\Pck\Bar)|(Boo&Baz) $obj2 = new Boo()
|
||||
) {}
|
||||
|
||||
/* testPHP82DNFTypesWithSpreadOperatorAndReference */
|
||||
function dnfInGlobalFunctionWithSpreadAndReference((Countable&MeMe)|iterable &$paramA, true|(Foo&Bar) ...$paramB) {}
|
||||
|
||||
/* testPHP82DNFTypesIllegalNullable */
|
||||
// Intentional fatal error - nullable operator cannot be combined with DNF.
|
||||
$dnf_closure = function (? ( MyClassA & /*comment*/ \Package\MyClassB & \Package\MyClassC ) $var): void {};
|
||||
|
||||
/* testPHP82DNFTypesInArrow */
|
||||
$dnf_arrow = fn((Hi&Ho)|FALSE &...$range): string => $a;
|
||||
|
||||
/* testFunctionCallFnPHPCS353-354 */
|
||||
$value = $obj->fn(true);
|
||||
|
||||
/* testClosureNoParams */
|
||||
function() {};
|
||||
|
||||
/* testClosure */
|
||||
function( $a = 'test' ) {};
|
||||
|
||||
/* testClosureUseNoParams */
|
||||
function() use() {};
|
||||
|
||||
/* testClosureUse */
|
||||
function() use( $foo, $bar ) {};
|
||||
|
||||
/* 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
|
||||
Vendored
+3182
File diff suppressed because it is too large
Load Diff
Vendored
+226
@@ -0,0 +1,226 @@
|
||||
<?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 {}
|
||||
|
||||
/* testPHP82DNFType */
|
||||
function hasDNFType() : bool|(Foo&Bar)|string {}
|
||||
|
||||
abstract class AbstractClass {
|
||||
/* testPHP82DNFTypeAbstractMethod */
|
||||
abstract protected function abstractMethodDNFType() : float|(Foo&Bar);
|
||||
}
|
||||
|
||||
/* testPHP82DNFTypeIllegalNullable */
|
||||
// Intentional fatal error - nullable operator cannot be combined with DNF.
|
||||
function illegalNullableDNF(): ?(A&\Pck\B)|bool {}
|
||||
|
||||
/* testPHP82DNFTypeClosure */
|
||||
$closure = function() : object|(namespace\Foo&Countable) {};
|
||||
|
||||
/* testPHP82DNFTypeFn */
|
||||
// Intentional fatal error - void type cannot be combined with DNF.
|
||||
$arrow = fn() : null|(Partially\Qualified&Traversable)|void => do_something();
|
||||
|
||||
/* testNotAFunction */
|
||||
return true;
|
||||
|
||||
/* testPhpcsIssue1264 */
|
||||
function foo() : array {
|
||||
echo $foo;
|
||||
}
|
||||
|
||||
/* testArrowFunctionArrayReturnValue */
|
||||
$fn = fn(): array => [a($a, $b)];
|
||||
|
||||
/* testArrowFunctionReturnByRef */
|
||||
fn&(?string $a) : ?string => $b;
|
||||
|
||||
/* testFunctionCallFnPHPCS353-354 */
|
||||
$value = $obj->fn(true);
|
||||
|
||||
/* testFunctionDeclarationNestedInTernaryPHPCS2975 */
|
||||
return (!$a ? [ new class { public function b(): c {} } ] : []);
|
||||
|
||||
/* testClosureWithUseNoReturnType */
|
||||
$closure = function () use($a) /*comment*/ {};
|
||||
|
||||
/* testClosureWithUseNoReturnTypeIllegalUseProp */
|
||||
$closure = function () use ($this->prop){};
|
||||
|
||||
/* testClosureWithUseWithReturnType */
|
||||
$closure = function () use /*comment*/ ($a): Type {};
|
||||
|
||||
/* testClosureWithUseMultiParamWithReturnType */
|
||||
$closure = function () use ($a, &$b, $c, $d, $e, $f, $g): ?array {};
|
||||
|
||||
/* testArrowFunctionLiveCoding */
|
||||
// Intentional parse error. This has to be the last test in the file.
|
||||
$fn = fn
|
||||
Vendored
+1562
File diff suppressed because it is too large
Load Diff
Vendored
+334
@@ -0,0 +1,334 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File:getTokensAsString method.
|
||||
*
|
||||
* @covers \PHP_CodeSniffer\Files\File::getTokensAsString
|
||||
*/
|
||||
final class GetTokensAsStringTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test passing a non-existent token pointer.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNonExistentToken()
|
||||
{
|
||||
$this->expectRunTimeException('The $start position for getTokensAsString() must exist in the token stack');
|
||||
|
||||
self::$phpcsFile->getTokensAsString(100000, 10);
|
||||
|
||||
}//end testNonExistentToken()
|
||||
|
||||
|
||||
/**
|
||||
* Test passing a non integer `$start`, like the result of a failed $phpcsFile->findNext().
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNonIntegerStart()
|
||||
{
|
||||
$this->expectRunTimeException('The $start position for getTokensAsString() must exist in the token stack');
|
||||
|
||||
self::$phpcsFile->getTokensAsString(false, 10);
|
||||
|
||||
}//end testNonIntegerStart()
|
||||
|
||||
|
||||
/**
|
||||
* Test passing a non integer `$length`.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNonIntegerLength()
|
||||
{
|
||||
$result = self::$phpcsFile->getTokensAsString(10, false);
|
||||
$this->assertSame('', $result);
|
||||
|
||||
$result = self::$phpcsFile->getTokensAsString(10, 1.5);
|
||||
$this->assertSame('', $result);
|
||||
|
||||
}//end testNonIntegerLength()
|
||||
|
||||
|
||||
/**
|
||||
* Test passing a zero or negative `$length`.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testLengthEqualToOrLessThanZero()
|
||||
{
|
||||
$result = self::$phpcsFile->getTokensAsString(10, -10);
|
||||
$this->assertSame('', $result);
|
||||
|
||||
$result = self::$phpcsFile->getTokensAsString(10, 0);
|
||||
$this->assertSame('', $result);
|
||||
|
||||
}//end testLengthEqualToOrLessThanZero()
|
||||
|
||||
|
||||
/**
|
||||
* Test passing a `$length` beyond the end of the file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testLengthBeyondEndOfFile()
|
||||
{
|
||||
$semicolon = $this->getTargetToken('/* testEndOfFile */', T_SEMICOLON);
|
||||
$result = self::$phpcsFile->getTokensAsString($semicolon, 20);
|
||||
$this->assertSame(
|
||||
';
|
||||
',
|
||||
$result
|
||||
);
|
||||
|
||||
}//end testLengthBeyondEndOfFile()
|
||||
|
||||
|
||||
/**
|
||||
* Test getting a token set as a string.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param int|string $startTokenType The type of token(s) to look for for the start of the string.
|
||||
* @param int $length Token length to get.
|
||||
* @param string $expected The expected function return value.
|
||||
*
|
||||
* @dataProvider dataGetTokensAsString
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetTokensAsString($testMarker, $startTokenType, $length, $expected)
|
||||
{
|
||||
$start = $this->getTargetToken($testMarker, $startTokenType);
|
||||
$result = self::$phpcsFile->getTokensAsString($start, $length);
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
}//end testGetTokensAsString()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testGetTokensAsString() For the array format.
|
||||
*
|
||||
* @return array<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
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
<?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;
|
||||
|
||||
/* testIntersectionIsNotReference */
|
||||
function intersect(Foo&Bar $param) {}
|
||||
|
||||
/* testDNFTypeIsNotReference */
|
||||
$fn = fn((Foo&\Bar)|null /* testParamPassByReference */ &$param) => $param;
|
||||
|
||||
/* testTokenizerIssue1284PHPCSlt280A */
|
||||
if ($foo) {}
|
||||
[&$a, /* testTokenizerIssue1284PHPCSlt280B */ &$b] = $c;
|
||||
|
||||
/* testTokenizerIssue1284PHPCSlt280C */
|
||||
if ($foo) {}
|
||||
[&$a, $b];
|
||||
+396
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File::isReference 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 PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File::isReference method.
|
||||
*
|
||||
* @covers \PHP_CodeSniffer\Files\File::isReference
|
||||
*/
|
||||
final class IsReferenceTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that false is returned when a non-"bitwise and" token is passed.
|
||||
*
|
||||
* @param string $testMarker Comment which precedes the test case.
|
||||
* @param array<int|string> $targetTokens Type of tokens to look for.
|
||||
*
|
||||
* @dataProvider dataNotBitwiseAndToken
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotBitwiseAndToken($testMarker, $targetTokens)
|
||||
{
|
||||
$targetTokens[] = T_BITWISE_AND;
|
||||
|
||||
$target = $this->getTargetToken($testMarker, $targetTokens);
|
||||
$this->assertFalse(self::$phpcsFile->isReference($target));
|
||||
|
||||
}//end testNotBitwiseAndToken()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNotBitwiseAndToken()
|
||||
*
|
||||
* @return array<string, array<string, string|array<int|string>>>
|
||||
*/
|
||||
public static function dataNotBitwiseAndToken()
|
||||
{
|
||||
return [
|
||||
'Not ampersand token at all' => [
|
||||
'testMarker' => '/* testBitwiseAndA */',
|
||||
'targetTokens' => [T_STRING],
|
||||
],
|
||||
'ampersand in intersection type' => [
|
||||
'testMarker' => '/* testIntersectionIsNotReference */',
|
||||
'targetTokens' => [T_TYPE_INTERSECTION],
|
||||
],
|
||||
'ampersand in DNF type' => [
|
||||
'testMarker' => '/* testDNFTypeIsNotReference */',
|
||||
'targetTokens' => [T_TYPE_INTERSECTION],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataNotBitwiseAndToken()
|
||||
|
||||
|
||||
/**
|
||||
* Test correctly identifying whether a "bitwise and" token is a reference or not.
|
||||
*
|
||||
* @param string $testMarker Comment which precedes the test case.
|
||||
* @param bool $expected Expected function output.
|
||||
*
|
||||
* @dataProvider dataIsReference
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testIsReference($testMarker, $expected)
|
||||
{
|
||||
$bitwiseAnd = $this->getTargetToken($testMarker, T_BITWISE_AND);
|
||||
$result = self::$phpcsFile->isReference($bitwiseAnd);
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
}//end testIsReference()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider for the IsReference test.
|
||||
*
|
||||
* @see testIsReference()
|
||||
*
|
||||
* @return array<string, array<string, string|bool>>
|
||||
*/
|
||||
public static function dataIsReference()
|
||||
{
|
||||
return [
|
||||
'issue-1971-list-first-in-file' => [
|
||||
'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271A */',
|
||||
'expected' => true,
|
||||
],
|
||||
'issue-1971-list-first-in-file-nested' => [
|
||||
'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271B */',
|
||||
'expected' => true,
|
||||
],
|
||||
'bitwise and: param in function call' => [
|
||||
'testMarker' => '/* testBitwiseAndA */',
|
||||
'expected' => false,
|
||||
],
|
||||
'bitwise and: in unkeyed short array, first value' => [
|
||||
'testMarker' => '/* testBitwiseAndB */',
|
||||
'expected' => false,
|
||||
],
|
||||
'bitwise and: in unkeyed short array, last value' => [
|
||||
'testMarker' => '/* testBitwiseAndC */',
|
||||
'expected' => false,
|
||||
],
|
||||
'bitwise and: in unkeyed long array, last value' => [
|
||||
'testMarker' => '/* testBitwiseAndD */',
|
||||
'expected' => false,
|
||||
],
|
||||
'bitwise and: in keyed short array, last value' => [
|
||||
'testMarker' => '/* testBitwiseAndE */',
|
||||
'expected' => false,
|
||||
],
|
||||
'bitwise and: in keyed long array, last value' => [
|
||||
'testMarker' => '/* testBitwiseAndF */',
|
||||
'expected' => false,
|
||||
],
|
||||
'bitwise and: in assignment' => [
|
||||
'testMarker' => '/* testBitwiseAndG */',
|
||||
'expected' => false,
|
||||
],
|
||||
'bitwise and: in param default value in function declaration' => [
|
||||
'testMarker' => '/* testBitwiseAndH */',
|
||||
'expected' => false,
|
||||
],
|
||||
'bitwise and: in param default value in closure declaration' => [
|
||||
'testMarker' => '/* testBitwiseAndI */',
|
||||
'expected' => false,
|
||||
],
|
||||
'reference: function declared to return by reference' => [
|
||||
'testMarker' => '/* testFunctionReturnByReference */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: only param in function declaration, pass by reference' => [
|
||||
'testMarker' => '/* testFunctionPassByReferenceA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: last param in function declaration, pass by reference' => [
|
||||
'testMarker' => '/* testFunctionPassByReferenceB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: only param in closure declaration, pass by reference' => [
|
||||
'testMarker' => '/* testFunctionPassByReferenceC */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: last param in closure declaration, pass by reference' => [
|
||||
'testMarker' => '/* testFunctionPassByReferenceD */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: typed param in function declaration, pass by reference' => [
|
||||
'testMarker' => '/* testFunctionPassByReferenceE */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: typed param in closure declaration, pass by reference' => [
|
||||
'testMarker' => '/* testFunctionPassByReferenceF */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: variadic param in function declaration, pass by reference' => [
|
||||
'testMarker' => '/* testFunctionPassByReferenceG */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: foreach value' => [
|
||||
'testMarker' => '/* testForeachValueByReference */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: foreach key' => [
|
||||
'testMarker' => '/* testForeachKeyByReference */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: keyed short array, first value, value by reference' => [
|
||||
'testMarker' => '/* testArrayValueByReferenceA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: keyed short array, last value, value by reference' => [
|
||||
'testMarker' => '/* testArrayValueByReferenceB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed short array, only value, value by reference' => [
|
||||
'testMarker' => '/* testArrayValueByReferenceC */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed short array, last value, value by reference' => [
|
||||
'testMarker' => '/* testArrayValueByReferenceD */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: keyed long array, first value, value by reference' => [
|
||||
'testMarker' => '/* testArrayValueByReferenceE */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: keyed long array, last value, value by reference' => [
|
||||
'testMarker' => '/* testArrayValueByReferenceF */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed long array, only value, value by reference' => [
|
||||
'testMarker' => '/* testArrayValueByReferenceG */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed long array, last value, value by reference' => [
|
||||
'testMarker' => '/* testArrayValueByReferenceH */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: variable, assign by reference' => [
|
||||
'testMarker' => '/* testAssignByReferenceA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: variable, assign by reference, spacing variation' => [
|
||||
'testMarker' => '/* testAssignByReferenceB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: variable, assign by reference, concat assign' => [
|
||||
'testMarker' => '/* testAssignByReferenceC */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: property, assign by reference' => [
|
||||
'testMarker' => '/* testAssignByReferenceD */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: function return value, assign by reference' => [
|
||||
'testMarker' => '/* testAssignByReferenceE */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: function return value, assign by reference, null coalesce assign' => [
|
||||
'testMarker' => '/* testAssignByReferenceF */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed short list, first var, assign by reference' => [
|
||||
'testMarker' => '/* testShortListAssignByReferenceNoKeyA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed short list, second var, assign by reference' => [
|
||||
'testMarker' => '/* testShortListAssignByReferenceNoKeyB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed short list, nested var, assign by reference' => [
|
||||
'testMarker' => '/* testNestedShortListAssignByReferenceNoKey */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed long list, second var, assign by reference' => [
|
||||
'testMarker' => '/* testLongListAssignByReferenceNoKeyA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed long list, first nested var, assign by reference' => [
|
||||
'testMarker' => '/* testLongListAssignByReferenceNoKeyB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: unkeyed long list, last nested var, assign by reference' => [
|
||||
'testMarker' => '/* testLongListAssignByReferenceNoKeyC */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: keyed short list, first nested var, assign by reference' => [
|
||||
'testMarker' => '/* testNestedShortListAssignByReferenceWithKeyA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: keyed short list, last nested var, assign by reference' => [
|
||||
'testMarker' => '/* testNestedShortListAssignByReferenceWithKeyB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: keyed long list, only var, assign by reference' => [
|
||||
'testMarker' => '/* testLongListAssignByReferenceWithKeyA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: first param in function call, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: last param in function call, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: property in function call, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceC */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: hierarchical self property in function call, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceD */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: hierarchical parent property in function call, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceE */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: hierarchical static property in function call, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceF */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: static property in function call, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceG */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: static property in function call, first with FQN, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceH */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: static property in function call, last with FQN, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceI */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: static property in function call, last with namespace relative name, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceJ */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: static property in function call, last with PQN, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferencePartiallyQualifiedName */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: new by reference' => [
|
||||
'testMarker' => '/* testNewByReferenceA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: new by reference as function call param' => [
|
||||
'testMarker' => '/* testNewByReferenceB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: closure use by reference' => [
|
||||
'testMarker' => '/* testUseByReference */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: closure use by reference, first param, with comment' => [
|
||||
'testMarker' => '/* testUseByReferenceWithCommentFirstParam */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: closure use by reference, last param, with comment' => [
|
||||
'testMarker' => '/* testUseByReferenceWithCommentSecondParam */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: arrow fn declared to return by reference' => [
|
||||
'testMarker' => '/* testArrowFunctionReturnByReference */',
|
||||
'expected' => true,
|
||||
],
|
||||
'bitwise and: first param default value in closure declaration' => [
|
||||
'testMarker' => '/* testBitwiseAndExactParameterA */',
|
||||
'expected' => false,
|
||||
],
|
||||
'reference: param in closure declaration, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceExactParameterB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: variadic param in closure declaration, pass by reference' => [
|
||||
'testMarker' => '/* testPassByReferenceExactParameterC */',
|
||||
'expected' => true,
|
||||
],
|
||||
'bitwise and: last param default value in closure declaration' => [
|
||||
'testMarker' => '/* testBitwiseAndExactParameterD */',
|
||||
'expected' => false,
|
||||
],
|
||||
'reference: typed param in arrow fn declaration, pass by reference' => [
|
||||
'testMarker' => '/* testArrowFunctionPassByReferenceA */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: variadic param in arrow fn declaration, pass by reference' => [
|
||||
'testMarker' => '/* testArrowFunctionPassByReferenceB */',
|
||||
'expected' => true,
|
||||
],
|
||||
'reference: closure declared to return by reference' => [
|
||||
'testMarker' => '/* testClosureReturnByReference */',
|
||||
'expected' => true,
|
||||
],
|
||||
'bitwise and: param default value in arrow fn declaration' => [
|
||||
'testMarker' => '/* testBitwiseAndArrowFunctionInDefault */',
|
||||
'expected' => false,
|
||||
],
|
||||
'reference: param pass by ref in arrow function' => [
|
||||
'testMarker' => '/* testParamPassByReference */',
|
||||
'expected' => true,
|
||||
],
|
||||
'issue-1284-short-list-directly-after-close-curly-control-structure' => [
|
||||
'testMarker' => '/* testTokenizerIssue1284PHPCSlt280A */',
|
||||
'expected' => true,
|
||||
],
|
||||
'issue-1284-short-list-directly-after-close-curly-control-structure-second-item' => [
|
||||
'testMarker' => '/* testTokenizerIssue1284PHPCSlt280B */',
|
||||
'expected' => true,
|
||||
],
|
||||
'issue-1284-short-array-directly-after-close-curly-control-structure' => [
|
||||
'testMarker' => '/* testTokenizerIssue1284PHPCSlt280C */',
|
||||
'expected' => true,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataIsReference()
|
||||
|
||||
|
||||
}//end class
|
||||
docker/streamline-src/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php
Vendored
+250
@@ -0,0 +1,250 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core\Filters;
|
||||
|
||||
use PHP_CodeSniffer\Filters\Filter;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Tests\ConfigDouble;
|
||||
use 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()
|
||||
|
||||
|
||||
/**
|
||||
* Clean up after finished test by resetting all static properties on the Config class to their default values.
|
||||
*
|
||||
* Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::tearDownAfterClass()}
|
||||
* method.
|
||||
*
|
||||
* @afterClass
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function reset()
|
||||
{
|
||||
// Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics.
|
||||
// The explicit method call prevents potential stray test-local references to the $config object
|
||||
// preventing the destructor from running the clean up (which without stray references would be
|
||||
// automagically triggered when `self::$phpcsFile` is reset, but we can't definitively rely on that).
|
||||
if (isset(self::$config) === true) {
|
||||
self::$config->__destruct();
|
||||
}
|
||||
|
||||
}//end reset()
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
Vendored
+268
@@ -0,0 +1,268 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core\Filters;
|
||||
|
||||
use PHP_CodeSniffer\Filters\GitModified;
|
||||
use 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('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('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
|
||||
Vendored
+268
@@ -0,0 +1,268 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core\Filters;
|
||||
|
||||
use PHP_CodeSniffer\Filters\GitStaged;
|
||||
use 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('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('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
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
<?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 PHP_CodeSniffer\Tests\Core\Ruleset;
|
||||
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Runner;
|
||||
use PHP_CodeSniffer\Tests\ConfigDouble;
|
||||
use 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 ShowSniffDeprecationsTest standard contains 10 sniffs'.PHP_EOL.PHP_EOL;
|
||||
|
||||
$expected .= 'TestStandard (10 sniffs)'.PHP_EOL;
|
||||
$expected .= '------------------------'.PHP_EOL;
|
||||
$expected .= ' TestStandard.Deprecated.WithLongReplacement *'.PHP_EOL;
|
||||
$expected .= ' TestStandard.Deprecated.WithoutReplacement *'.PHP_EOL;
|
||||
$expected .= ' TestStandard.Deprecated.WithReplacement *'.PHP_EOL;
|
||||
$expected .= ' TestStandard.Deprecated.WithReplacementContainingLinuxNewlines *'.PHP_EOL;
|
||||
$expected .= ' TestStandard.Deprecated.WithReplacementContainingNewlines *'.PHP_EOL;
|
||||
$expected .= ' TestStandard.SetProperty.AllowedAsDeclared'.PHP_EOL;
|
||||
$expected .= ' TestStandard.SetProperty.AllowedViaMagicMethod'.PHP_EOL;
|
||||
$expected .= ' TestStandard.SetProperty.AllowedViaStdClass'.PHP_EOL;
|
||||
$expected .= ' TestStandard.SetProperty.NotAllowedViaAttribute'.PHP_EOL;
|
||||
$expected .= ' TestStandard.SetProperty.PropertyTypeHandling'.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()
|
||||
{
|
||||
if (PHP_CODESNIFFER_CBF === true) {
|
||||
$this->markTestSkipped('This test needs CS mode to run');
|
||||
}
|
||||
|
||||
$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();
|
||||
$runner->runPHPCS();
|
||||
|
||||
}//end testExplainWillExplainEachStandardSeparately()
|
||||
|
||||
|
||||
}//end class
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Ruleset class using a Windows-style absolute path to include a sniff.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2019 Juliette Reinders Folmer. All rights reserved.
|
||||
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Ruleset;
|
||||
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Tests\ConfigDouble;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Ruleset class using a Windows-style absolute path to include a sniff.
|
||||
*
|
||||
* @covers \PHP_CodeSniffer\Ruleset
|
||||
* @requires OS ^WIN.*.
|
||||
* @group Windows
|
||||
*/
|
||||
final class RuleInclusionAbsoluteWindowsTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* The Ruleset object.
|
||||
*
|
||||
* @var \PHP_CodeSniffer\Ruleset
|
||||
*/
|
||||
protected $ruleset;
|
||||
|
||||
/**
|
||||
* Path to the ruleset file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $standard = '';
|
||||
|
||||
/**
|
||||
* The original content of the ruleset.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $contents = '';
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the config and ruleset objects.
|
||||
*
|
||||
* @before
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initializeConfigAndRuleset()
|
||||
{
|
||||
$this->standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml';
|
||||
$repoRootDir = dirname(dirname(dirname(__DIR__)));
|
||||
|
||||
// On-the-fly adjust the ruleset test file to be able to test sniffs included with absolute paths.
|
||||
$contents = file_get_contents($this->standard);
|
||||
$this->contents = $contents;
|
||||
|
||||
$adjusted = str_replace('%path_slash_back%', $repoRootDir, $contents);
|
||||
|
||||
if (file_put_contents($this->standard, $adjusted) === false) {
|
||||
$this->markTestSkipped('On the fly ruleset adjustment failed');
|
||||
}
|
||||
|
||||
// Initialize the config and ruleset objects for the test.
|
||||
$config = new ConfigDouble(["--standard={$this->standard}"]);
|
||||
$this->ruleset = new Ruleset($config);
|
||||
|
||||
}//end initializeConfigAndRuleset()
|
||||
|
||||
|
||||
/**
|
||||
* Reset ruleset file.
|
||||
*
|
||||
* @after
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetRuleset()
|
||||
{
|
||||
file_put_contents($this->standard, $this->contents);
|
||||
|
||||
}//end resetRuleset()
|
||||
|
||||
|
||||
/**
|
||||
* Test that sniffs registed with a Windows absolute path are correctly recognized and that
|
||||
* properties are correctly set for them.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testWindowsStylePathRuleInclusion()
|
||||
{
|
||||
// Test that the sniff is correctly registered.
|
||||
$this->assertCount(1, $this->ruleset->sniffCodes);
|
||||
$this->assertArrayHasKey('Generic.Formatting.SpaceAfterCast', $this->ruleset->sniffCodes);
|
||||
$this->assertSame(
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Formatting\SpaceAfterCastSniff',
|
||||
$this->ruleset->sniffCodes['Generic.Formatting.SpaceAfterCast']
|
||||
);
|
||||
|
||||
// Test that the sniff property is correctly set.
|
||||
$this->assertSame(
|
||||
'10',
|
||||
$this->ruleset->sniffs['PHP_CodeSniffer\Standards\Generic\Sniffs\Formatting\SpaceAfterCastSniff']->spacing
|
||||
);
|
||||
|
||||
}//end testWindowsStylePathRuleInclusion()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+479
@@ -0,0 +1,479 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Ruleset class.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2019 Juliette Reinders Folmer. All rights reserved.
|
||||
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Ruleset;
|
||||
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Tests\ConfigDouble;
|
||||
use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase;
|
||||
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Ruleset class.
|
||||
*
|
||||
* @covers \PHP_CodeSniffer\Ruleset
|
||||
*/
|
||||
final class RuleInclusionTest extends AbstractRulesetTestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* The Ruleset object.
|
||||
*
|
||||
* @var \PHP_CodeSniffer\Ruleset
|
||||
*/
|
||||
protected static $ruleset;
|
||||
|
||||
/**
|
||||
* Path to the ruleset file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $standard = '';
|
||||
|
||||
/**
|
||||
* The original content of the ruleset.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $contents = '';
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the config and ruleset objects based on the `RuleInclusionTest.xml` ruleset file.
|
||||
*
|
||||
* @before
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function initializeConfigAndRuleset()
|
||||
{
|
||||
if (self::$standard === '') {
|
||||
$standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml';
|
||||
self::$standard = $standard;
|
||||
|
||||
// On-the-fly adjust the ruleset test file to be able to test
|
||||
// sniffs included with relative paths.
|
||||
$contents = file_get_contents($standard);
|
||||
self::$contents = $contents;
|
||||
|
||||
$repoRootDir = basename(dirname(dirname(dirname(__DIR__))));
|
||||
|
||||
$newPath = $repoRootDir;
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
$newPath = str_replace('\\', '/', $repoRootDir);
|
||||
}
|
||||
|
||||
$adjusted = str_replace('%path_root_dir%', $newPath, $contents);
|
||||
|
||||
if (file_put_contents($standard, $adjusted) === false) {
|
||||
self::markTestSkipped('On the fly ruleset adjustment failed');
|
||||
}
|
||||
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
self::$ruleset = new Ruleset($config);
|
||||
}//end if
|
||||
|
||||
}//end initializeConfigAndRuleset()
|
||||
|
||||
|
||||
/**
|
||||
* Reset ruleset file.
|
||||
*
|
||||
* @after
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetRuleset()
|
||||
{
|
||||
file_put_contents(self::$standard, self::$contents);
|
||||
|
||||
}//end resetRuleset()
|
||||
|
||||
|
||||
/**
|
||||
* Test that sniffs are registered.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHasSniffCodes()
|
||||
{
|
||||
$this->assertCount(49, self::$ruleset->sniffCodes);
|
||||
|
||||
}//end testHasSniffCodes()
|
||||
|
||||
|
||||
/**
|
||||
* Test that sniffs are correctly registered, independently of the syntax used to include the sniff.
|
||||
*
|
||||
* @param string $key Expected array key.
|
||||
* @param string $value Expected array value.
|
||||
*
|
||||
* @dataProvider dataRegisteredSniffCodes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRegisteredSniffCodes($key, $value)
|
||||
{
|
||||
$this->assertArrayHasKey($key, self::$ruleset->sniffCodes);
|
||||
$this->assertSame($value, self::$ruleset->sniffCodes[$key]);
|
||||
|
||||
}//end testRegisteredSniffCodes()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see self::testRegisteredSniffCodes()
|
||||
*
|
||||
* @return array<array<string>>
|
||||
*/
|
||||
public static function dataRegisteredSniffCodes()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'PSR2.Classes.ClassDeclaration',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.Classes.PropertyDeclaration',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\PropertyDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.ControlStructures.ControlStructureSpacing',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\ControlStructureSpacingSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.ControlStructures.ElseIfDeclaration',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\ElseIfDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.ControlStructures.SwitchDeclaration',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\SwitchDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.Files.ClosingTag',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\Files\ClosingTagSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.Files.EndFileNewline',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\Files\EndFileNewlineSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.Methods.FunctionCallSignature',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionCallSignatureSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.Methods.FunctionClosingBrace',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionClosingBraceSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.Methods.MethodDeclaration',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\MethodDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.Namespaces.NamespaceDeclaration',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\Namespaces\NamespaceDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'PSR2.Namespaces.UseDeclaration',
|
||||
'PHP_CodeSniffer\Standards\PSR2\Sniffs\Namespaces\UseDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'PSR1.Classes.ClassDeclaration',
|
||||
'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'PSR1.Files.SideEffects',
|
||||
'PHP_CodeSniffer\Standards\PSR1\Sniffs\Files\SideEffectsSniff',
|
||||
],
|
||||
[
|
||||
'PSR1.Methods.CamelCapsMethodName',
|
||||
'PHP_CodeSniffer\Standards\PSR1\Sniffs\Methods\CamelCapsMethodNameSniff',
|
||||
],
|
||||
[
|
||||
'Generic.PHP.DisallowAlternativePHPTags',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\DisallowAlternativePHPTagsSniff',
|
||||
],
|
||||
[
|
||||
'Generic.PHP.DisallowShortOpenTag',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\DisallowShortOpenTagSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Files.ByteOrderMark',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\ByteOrderMarkSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.Classes.ValidClassName',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\Classes\ValidClassNameSniff',
|
||||
],
|
||||
[
|
||||
'Generic.NamingConventions.UpperCaseConstantName',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\UpperCaseConstantNameSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Files.LineEndings',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineEndingsSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Files.LineLength',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.WhiteSpace.SuperfluousWhitespace',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\SuperfluousWhitespaceSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Formatting.DisallowMultipleStatements',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Formatting\DisallowMultipleStatementsSniff',
|
||||
],
|
||||
[
|
||||
'Generic.WhiteSpace.ScopeIndent',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff',
|
||||
],
|
||||
[
|
||||
'Generic.WhiteSpace.DisallowTabIndent',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\DisallowTabIndentSniff',
|
||||
],
|
||||
[
|
||||
'Generic.PHP.LowerCaseKeyword',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseKeywordSniff',
|
||||
],
|
||||
[
|
||||
'Generic.PHP.LowerCaseConstant',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseConstantSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.Scope.MethodScope',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\Scope\MethodScopeSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.WhiteSpace.ScopeKeywordSpacing',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeKeywordSpacingSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.Functions.FunctionDeclaration',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\FunctionDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.Functions.LowercaseFunctionKeywords',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\LowercaseFunctionKeywordsSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.Functions.FunctionDeclarationArgumentSpacing',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\FunctionDeclarationArgumentSpacingSniff',
|
||||
],
|
||||
[
|
||||
'PEAR.Functions.ValidDefaultValue',
|
||||
'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\ValidDefaultValueSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.Functions.MultiLineFunctionDeclaration',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\MultiLineFunctionDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Functions.FunctionCallArgumentSpacing',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Functions\FunctionCallArgumentSpacingSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.ControlStructures.ControlSignature',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\ControlSignatureSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.WhiteSpace.ControlStructureSpacing',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ControlStructureSpacingSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.WhiteSpace.ScopeClosingBrace',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeClosingBraceSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.ControlStructures.ForEachLoopDeclaration',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\ForEachLoopDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.ControlStructures.ForLoopDeclaration',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\ForLoopDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'Squiz.ControlStructures.LowercaseDeclaration',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\LowercaseDeclarationSniff',
|
||||
],
|
||||
[
|
||||
'Generic.ControlStructures.InlineControlStructure',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\ControlStructures\InlineControlStructureSniff',
|
||||
],
|
||||
[
|
||||
'PSR12.Operators.OperatorSpacing',
|
||||
'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Arrays.ArrayIndent',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Metrics.CyclomaticComplexity',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff',
|
||||
],
|
||||
[
|
||||
'Squiz.Files.FileExtension',
|
||||
'PHP_CodeSniffer\Standards\Squiz\Sniffs\Files\FileExtensionSniff',
|
||||
],
|
||||
[
|
||||
'Generic.NamingConventions.CamelCapsFunctionName',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Metrics.NestingLevel',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataRegisteredSniffCodes()
|
||||
|
||||
|
||||
/**
|
||||
* Test that setting properties for standards, categories, sniffs works for all supported rule
|
||||
* inclusion methods.
|
||||
*
|
||||
* @param string $sniffClass The name of the sniff class.
|
||||
* @param string $propertyName The name of the changed property.
|
||||
* @param string|int|bool $expectedValue The value expected for the property.
|
||||
*
|
||||
* @dataProvider dataSettingProperties
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSettingProperties($sniffClass, $propertyName, $expectedValue)
|
||||
{
|
||||
$this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs);
|
||||
$this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$sniffClass]);
|
||||
|
||||
$actualValue = self::$ruleset->sniffs[$sniffClass]->$propertyName;
|
||||
$this->assertSame($expectedValue, $actualValue);
|
||||
|
||||
}//end testSettingProperties()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see self::testSettingProperties()
|
||||
*
|
||||
* @return array<string, array<string, string|int|bool>>
|
||||
*/
|
||||
public static function dataSettingProperties()
|
||||
{
|
||||
return [
|
||||
'Set property for complete standard: PSR2 ClassDeclaration' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff',
|
||||
'propertyName' => 'indent',
|
||||
'expectedValue' => '20',
|
||||
],
|
||||
'Set property for complete standard: PSR2 SwitchDeclaration' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\SwitchDeclarationSniff',
|
||||
'propertyName' => 'indent',
|
||||
'expectedValue' => '20',
|
||||
],
|
||||
'Set property for complete standard: PSR2 FunctionCallSignature' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionCallSignatureSniff',
|
||||
'propertyName' => 'indent',
|
||||
'expectedValue' => '20',
|
||||
],
|
||||
'Set property for complete category: PSR12 OperatorSpacing' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff',
|
||||
'propertyName' => 'ignoreSpacingBeforeAssignments',
|
||||
'expectedValue' => false,
|
||||
],
|
||||
'Set property for individual sniff: Generic ArrayIndent' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff',
|
||||
'propertyName' => 'indent',
|
||||
'expectedValue' => '2',
|
||||
],
|
||||
'Set property for individual sniff using sniff file inclusion: Generic LineLength' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff',
|
||||
'propertyName' => 'lineLimit',
|
||||
'expectedValue' => '10',
|
||||
],
|
||||
'Set property for individual sniff using sniff file inclusion: CamelCapsFunctionName' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff',
|
||||
'propertyName' => 'strict',
|
||||
'expectedValue' => false,
|
||||
],
|
||||
'Set property for individual sniff via included ruleset: NestingLevel - nestingLevel' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff',
|
||||
'propertyName' => 'nestingLevel',
|
||||
'expectedValue' => '2',
|
||||
],
|
||||
'Set property for all sniffs in an included ruleset: NestingLevel - absoluteNestingLevel' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff',
|
||||
'propertyName' => 'absoluteNestingLevel',
|
||||
'expectedValue' => true,
|
||||
],
|
||||
|
||||
// Testing that setting a property at error code level does *not* work.
|
||||
'Set property for error code will not change the sniff property value: CyclomaticComplexity' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff',
|
||||
'propertyName' => 'complexity',
|
||||
'expectedValue' => 10,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataSettingProperties()
|
||||
|
||||
|
||||
/**
|
||||
* Test that setting properties for standards, categories on sniffs which don't support the property will
|
||||
* silently ignore the property and not set it.
|
||||
*
|
||||
* @param string $sniffClass The name of the sniff class.
|
||||
* @param string $propertyName The name of the property which should not be set.
|
||||
*
|
||||
* @dataProvider dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails($sniffClass, $propertyName)
|
||||
{
|
||||
$this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs');
|
||||
$this->assertXObjectNotHasProperty($propertyName, self::$ruleset->sniffs[$sniffClass]);
|
||||
|
||||
}//end testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see self::testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails()
|
||||
*
|
||||
* @return array<string, array>string, string>>
|
||||
*/
|
||||
public static function dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails()
|
||||
{
|
||||
return [
|
||||
'Set property for complete standard: PSR2 ClassDeclaration' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff',
|
||||
'propertyName' => 'setforallsniffs',
|
||||
],
|
||||
'Set property for complete standard: PSR2 FunctionCallSignature' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionCallSignatureSniff',
|
||||
'propertyName' => 'setforallsniffs',
|
||||
],
|
||||
'Set property for complete category: PSR12 OperatorSpacing' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff',
|
||||
'propertyName' => 'setforallincategory',
|
||||
],
|
||||
'Set property for all sniffs in included category directory' => [
|
||||
'sniffClass' => 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Files\FileExtensionSniff',
|
||||
'propertyName' => 'setforsquizfilessniffs',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="RuleInclusionTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="PSR2">
|
||||
<properties>
|
||||
<property name="setforallsniffs" value="true" />
|
||||
<property name="indent" value="20" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="PSR12.Operators">
|
||||
<properties>
|
||||
<property name="setforallincategory" value="true" />
|
||||
<property name="ignoreSpacingBeforeAssignments" value="false" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="Generic.Arrays.ArrayIndent">
|
||||
<properties>
|
||||
<property name="indent" value="2" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="Generic.Metrics.CyclomaticComplexity.MaxExceeded">
|
||||
<properties>
|
||||
<property name="complexity" value="50" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- Sniff directory include. -->
|
||||
<rule ref="./src/Standards/Squiz/Sniffs/Files/">
|
||||
<properties>
|
||||
<property name="setforsquizfilessniffs" value="true" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- Sniff file include. -->
|
||||
<rule ref="./src/Standards/Generic/Sniffs/Files/LineLengthSniff.php">
|
||||
<properties>
|
||||
<property name="lineLimit" value="10" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="./../%path_root_dir%/src/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php">
|
||||
<properties>
|
||||
<property name="strict" value="false" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- Ruleset file include. -->
|
||||
<rule ref="./RuleInclusionTest-include.xml">
|
||||
<!-- Property being set for all sniffs included in this ruleset. -->
|
||||
<properties>
|
||||
<property name="absoluteNestingLevel" value="true" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="SetSniffPropertyTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="./tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedAsDeclaredSniff.php">
|
||||
<properties>
|
||||
<property name="arbitrarystring" value="arbitraryvalue"/>
|
||||
<property name="arbitraryarray" type="array">
|
||||
<element key="mykey" value="myvalue"/>
|
||||
</property>
|
||||
<property name="arbitraryarray" type="array" extend="true">
|
||||
<element key="otherkey" value="othervalue"/>
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="SetSniffPropertyTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="./tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaMagicMethodSniff.php">
|
||||
<properties>
|
||||
<property name="arbitrarystring" value="arbitraryvalue"/>
|
||||
<property name="arbitraryarray" type="array">
|
||||
<element key="mykey" value="myvalue"/>
|
||||
</property>
|
||||
<property name="arbitraryarray" type="array" extend="true">
|
||||
<element key="otherkey" value="othervalue"/>
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="SetSniffPropertyTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="./tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php">
|
||||
<properties>
|
||||
<property name="arbitrarystring" value="arbitraryvalue"/>
|
||||
<property name="arbitraryarray" type="array">
|
||||
<element key="mykey" value="myvalue"/>
|
||||
</property>
|
||||
<property name="arbitraryarray" type="array" extend="true">
|
||||
<element key="otherkey" value="othervalue"/>
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="SetSniffPropertyTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="PEAR.Functions">
|
||||
<properties>
|
||||
<property name="indent" value="10"/>
|
||||
</properties>
|
||||
</rule>
|
||||
</ruleset>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="SetSniffPropertyTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="Generic.Arrays">
|
||||
<properties>
|
||||
<property name="doesnotexist" value="2"/>
|
||||
</properties>
|
||||
</rule>
|
||||
</ruleset>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="SetSniffPropertyTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="Generic">
|
||||
<properties>
|
||||
<property name="doesnotexist" value="2"/>
|
||||
</properties>
|
||||
</rule>
|
||||
</ruleset>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="SetSniffPropertyTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="./tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/NotAllowedViaAttributeSniff.php">
|
||||
<properties>
|
||||
<property name="arbitrarystring" value="arbitraryvalue"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="SetSniffPropertyTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="Generic.Arrays.ArrayIndent">
|
||||
<properties>
|
||||
<property name="indentation" value="2"/>
|
||||
</properties>
|
||||
</rule>
|
||||
</ruleset>
|
||||
Vendored
+421
@@ -0,0 +1,421 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the handling of properties being set via the ruleset.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2022 Juliette Reinders Folmer. All rights reserved.
|
||||
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Ruleset;
|
||||
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Tests\ConfigDouble;
|
||||
use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase;
|
||||
use ReflectionObject;
|
||||
|
||||
/**
|
||||
* These tests specifically focus on the changes made to work around the PHP 8.2 dynamic properties deprecation.
|
||||
*
|
||||
* @covers \PHP_CodeSniffer\Ruleset::setSniffProperty
|
||||
*/
|
||||
final class SetSniffPropertyTest extends AbstractRulesetTestCase
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that setting a property via the ruleset works in all situations which allow for it.
|
||||
*
|
||||
* @param string $name Name of the test. Used for the sniff name, the ruleset file name etc.
|
||||
*
|
||||
* @dataProvider dataSniffPropertiesGetSetWhenAllowed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSniffPropertiesGetSetWhenAllowed($name)
|
||||
{
|
||||
$sniffCode = "TestStandard.SetProperty.{$name}";
|
||||
$sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff';
|
||||
$properties = [
|
||||
'arbitrarystring' => 'arbitraryvalue',
|
||||
'arbitraryarray' => [
|
||||
'mykey' => 'myvalue',
|
||||
'otherkey' => 'othervalue',
|
||||
],
|
||||
];
|
||||
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__."/SetProperty{$name}Test.xml";
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
// Verify that the sniff has been registered.
|
||||
$this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered');
|
||||
|
||||
// Verify that our target sniff has been registered.
|
||||
$this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered');
|
||||
$this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class');
|
||||
|
||||
// Test that the property as declared in the ruleset has been set on the sniff.
|
||||
$this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs');
|
||||
|
||||
$sniffObject = $ruleset->sniffs[$sniffClass];
|
||||
foreach ($properties as $name => $expectedValue) {
|
||||
$this->assertSame($expectedValue, $sniffObject->$name, 'Property value not set to expected value');
|
||||
}
|
||||
|
||||
}//end testSniffPropertiesGetSetWhenAllowed()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see self::testSniffPropertiesGetSetWhenAllowed()
|
||||
*
|
||||
* @return array<string, array<string>>
|
||||
*/
|
||||
public static function dataSniffPropertiesGetSetWhenAllowed()
|
||||
{
|
||||
return [
|
||||
'Property allowed as explicitly declared' => ['AllowedAsDeclared'],
|
||||
'Property allowed as sniff extends stdClass' => ['AllowedViaStdClass'],
|
||||
'Property allowed as sniff has magic __set() method' => ['AllowedViaMagicMethod'],
|
||||
];
|
||||
|
||||
}//end dataSniffPropertiesGetSetWhenAllowed()
|
||||
|
||||
|
||||
/**
|
||||
* Test that setting a property for a category will apply it correctly to those sniffs which support the
|
||||
* property, but won't apply it to sniffs which don't.
|
||||
*
|
||||
* Note: this test intentionally uses the `PEAR.Functions` category as two sniffs in that category
|
||||
* have a public property with the same name (`indent`) and one sniff doesn't, which makes it a great
|
||||
* test case for this.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSetPropertyAppliesPropertyToMultipleSniffsInCategory()
|
||||
{
|
||||
$propertyName = 'indent';
|
||||
$expectedValue = '10';
|
||||
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__.'/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml';
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
// Test that the two sniffs which support the property have received the value.
|
||||
$sniffClass = 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\FunctionCallSignatureSniff';
|
||||
$this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs');
|
||||
$sniffObject = $ruleset->sniffs[$sniffClass];
|
||||
$this->assertSame($expectedValue, $sniffObject->$propertyName, 'Property value not set to expected value for '.$sniffClass);
|
||||
|
||||
$sniffClass = 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\FunctionDeclarationSniff';
|
||||
$this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs');
|
||||
$sniffObject = $ruleset->sniffs[$sniffClass];
|
||||
$this->assertSame($expectedValue, $sniffObject->$propertyName, 'Property value not set to expected value for '.$sniffClass);
|
||||
|
||||
// Test that the property doesn't get set for the one sniff which doesn't support the property.
|
||||
$sniffClass = 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\ValidDefaultValueSniff';
|
||||
$this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs');
|
||||
|
||||
$hasProperty = (new ReflectionObject($ruleset->sniffs[$sniffClass]))->hasProperty($propertyName);
|
||||
$errorMsg = sprintf('Property %s registered for sniff %s which does not support it', $propertyName, $sniffClass);
|
||||
$this->assertFalse($hasProperty, $errorMsg);
|
||||
|
||||
}//end testSetPropertyAppliesPropertyToMultipleSniffsInCategory()
|
||||
|
||||
|
||||
/**
|
||||
* Test that attempting to set a non-existent property directly on a sniff will throw an error
|
||||
* when the sniff does not explicitly declare the property, extends stdClass or has magic methods.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSetPropertyThrowsErrorOnInvalidProperty()
|
||||
{
|
||||
$exceptionMsg = 'Ruleset invalid. Property "indentation" does not exist on sniff Generic.Arrays.ArrayIndent';
|
||||
$this->expectRuntimeExceptionMessage($exceptionMsg);
|
||||
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__.'/SetPropertyThrowsErrorOnInvalidPropertyTest.xml';
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
new Ruleset($config);
|
||||
|
||||
}//end testSetPropertyThrowsErrorOnInvalidProperty()
|
||||
|
||||
|
||||
/**
|
||||
* Test that attempting to set a non-existent property directly on a sniff will throw an error
|
||||
* when the sniff does not explicitly declare the property, extends stdClass or has magic methods,
|
||||
* even though the sniff has the PHP 8.2 `#[AllowDynamicProperties]` attribute set.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute()
|
||||
{
|
||||
$exceptionMsg = 'Ruleset invalid. Property "arbitrarystring" does not exist on sniff TestStandard.SetProperty.NotAllowedViaAttribute';
|
||||
$this->expectRuntimeExceptionMessage($exceptionMsg);
|
||||
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__.'/SetPropertyNotAllowedViaAttributeTest.xml';
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
new Ruleset($config);
|
||||
|
||||
}//end testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute()
|
||||
|
||||
|
||||
/**
|
||||
* Test that attempting to set a non-existent property on a sniff when the property directive is
|
||||
* for the whole standard, does not yield an error.
|
||||
*
|
||||
* @doesNotPerformAssertions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandard()
|
||||
{
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__.'/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml';
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
new Ruleset($config);
|
||||
|
||||
}//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandard()
|
||||
|
||||
|
||||
/**
|
||||
* Test that attempting to set a non-existent property on a sniff when the property directive is
|
||||
* for a whole category, does not yield an error.
|
||||
*
|
||||
* @doesNotPerformAssertions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategory()
|
||||
{
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__.'/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml';
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
new Ruleset($config);
|
||||
|
||||
}//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategory()
|
||||
|
||||
|
||||
/**
|
||||
* Test that attempting to set a property for a sniff which isn't registered will be ignored.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDirectCallIgnoredPropertyForUnusedSniff()
|
||||
{
|
||||
$sniffCode = 'Generic.Formatting.SpaceAfterCast';
|
||||
$sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Formatting\\SpaceAfterCastSniff';
|
||||
|
||||
// Set up the ruleset.
|
||||
$config = new ConfigDouble(['--standard=PSR1']);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$ruleset->setSniffProperty(
|
||||
$sniffClass,
|
||||
'ignoreNewlines',
|
||||
[
|
||||
'scope' => 'sniff',
|
||||
'value' => true,
|
||||
]
|
||||
);
|
||||
|
||||
// Verify that there are sniffs registered.
|
||||
$this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered');
|
||||
|
||||
// Verify that our target sniff has NOT been registered after attempting to set the property.
|
||||
$this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, 'Unused sniff was registered in sniffCodes, but shouldn\'t have been');
|
||||
$this->assertArrayNotHasKey($sniffClass, $ruleset->sniffs, 'Unused sniff was registered in sniffs, but shouldn\'t have been');
|
||||
|
||||
}//end testDirectCallIgnoredPropertyForUnusedSniff()
|
||||
|
||||
|
||||
/**
|
||||
* Test that setting a property via a direct call to the Ruleset::setSniffProperty() method
|
||||
* sets the property correctly when using the new $settings array format.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDirectCallWithNewArrayFormatSetsProperty()
|
||||
{
|
||||
$name = 'AllowedAsDeclared';
|
||||
$sniffCode = "TestStandard.SetProperty.{$name}";
|
||||
$sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff';
|
||||
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__."/SetProperty{$name}Test.xml";
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$propertyName = 'arbitrarystring';
|
||||
$propertyValue = 'new value';
|
||||
|
||||
$ruleset->setSniffProperty(
|
||||
$sniffClass,
|
||||
$propertyName,
|
||||
[
|
||||
'scope' => 'sniff',
|
||||
'value' => $propertyValue,
|
||||
]
|
||||
);
|
||||
|
||||
// Verify that the sniff has been registered.
|
||||
$this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered');
|
||||
|
||||
// Verify that our target sniff has been registered.
|
||||
$this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered');
|
||||
$this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class');
|
||||
|
||||
// Test that the property as declared in the ruleset has been set on the sniff.
|
||||
$this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs');
|
||||
|
||||
$sniffObject = $ruleset->sniffs[$sniffClass];
|
||||
$this->assertSame($propertyValue, $sniffObject->$propertyName, 'Property value not set to expected value');
|
||||
|
||||
}//end testDirectCallWithNewArrayFormatSetsProperty()
|
||||
|
||||
|
||||
/**
|
||||
* Test that setting a property via a direct call to the Ruleset::setSniffProperty() method
|
||||
* sets the property correctly when using the old $settings array format.
|
||||
*
|
||||
* Tested by silencing the deprecation notice as otherwise the test would fail on the deprecation notice.
|
||||
*
|
||||
* @param mixed $propertyValue Value for the property to set.
|
||||
*
|
||||
* @dataProvider dataDirectCallWithOldArrayFormatSetsProperty
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDirectCallWithOldArrayFormatSetsProperty($propertyValue)
|
||||
{
|
||||
$name = 'AllowedAsDeclared';
|
||||
$sniffCode = "TestStandard.SetProperty.{$name}";
|
||||
$sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff';
|
||||
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__."/SetProperty{$name}Test.xml";
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$propertyName = 'arbitrarystring';
|
||||
|
||||
@$ruleset->setSniffProperty(
|
||||
$sniffClass,
|
||||
$propertyName,
|
||||
$propertyValue
|
||||
);
|
||||
|
||||
// Verify that the sniff has been registered.
|
||||
$this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered');
|
||||
|
||||
// Verify that our target sniff has been registered.
|
||||
$this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered');
|
||||
$this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class');
|
||||
|
||||
// Test that the property as declared in the ruleset has been set on the sniff.
|
||||
$this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs');
|
||||
|
||||
$sniffObject = $ruleset->sniffs[$sniffClass];
|
||||
$this->assertSame($propertyValue, $sniffObject->$propertyName, 'Property value not set to expected value');
|
||||
|
||||
}//end testDirectCallWithOldArrayFormatSetsProperty()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see self::testDirectCallWithOldArrayFormatSetsProperty()
|
||||
*
|
||||
* @return array<string, array<string, mixed>>
|
||||
*/
|
||||
public static function dataDirectCallWithOldArrayFormatSetsProperty()
|
||||
{
|
||||
return [
|
||||
'Property value is not an array (boolean)' => [
|
||||
'propertyValue' => false,
|
||||
],
|
||||
'Property value is not an array (string)' => [
|
||||
'propertyValue' => 'a string',
|
||||
],
|
||||
'Property value is an empty array' => [
|
||||
'propertyValue' => [],
|
||||
],
|
||||
'Property value is an array without keys' => [
|
||||
'propertyValue' => [
|
||||
'value',
|
||||
false,
|
||||
],
|
||||
],
|
||||
'Property value is an array without the "scope" or "value" keys' => [
|
||||
'propertyValue' => [
|
||||
'key1' => 'value',
|
||||
'key2' => false,
|
||||
],
|
||||
],
|
||||
'Property value is an array without the "scope" key' => [
|
||||
'propertyValue' => [
|
||||
'key1' => 'value',
|
||||
'value' => true,
|
||||
],
|
||||
],
|
||||
'Property value is an array without the "value" key' => [
|
||||
'propertyValue' => [
|
||||
'scope' => 'value',
|
||||
'key2' => 1234,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataDirectCallWithOldArrayFormatSetsProperty()
|
||||
|
||||
|
||||
/**
|
||||
* Test that setting a property via a direct call to the Ruleset::setSniffProperty() method
|
||||
* throws a deprecation notice when using the old $settings array format.
|
||||
*
|
||||
* Note: as PHPUnit stops as soon as it sees the deprecation notice, the setting of the property
|
||||
* value is not tested here.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDirectCallWithOldArrayFormatThrowsDeprecationNotice()
|
||||
{
|
||||
$exceptionClass = 'PHPUnit\Framework\Error\Deprecated';
|
||||
if (class_exists($exceptionClass) === false) {
|
||||
$exceptionClass = 'PHPUnit_Framework_Error_Deprecated';
|
||||
}
|
||||
|
||||
$exceptionMsg = 'the format of the $settings parameter has changed from (mixed) $value to array(\'scope\' => \'sniff|standard\', \'value\' => $value). Please update your integration code. See PR #3629 for more information.';
|
||||
|
||||
if (method_exists($this, 'expectException') === true) {
|
||||
$this->expectException($exceptionClass);
|
||||
$this->expectExceptionMessage($exceptionMsg);
|
||||
} else {
|
||||
// PHPUnit < 5.2.0.
|
||||
$this->setExpectedException($exceptionClass, $exceptionMsg);
|
||||
}
|
||||
|
||||
$name = 'AllowedAsDeclared';
|
||||
$sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff';
|
||||
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__."/SetProperty{$name}Test.xml";
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$ruleset->setSniffProperty(
|
||||
$sniffClass,
|
||||
'arbitrarystring',
|
||||
['key' => 'value']
|
||||
);
|
||||
|
||||
}//end testDirectCallWithOldArrayFormatThrowsDeprecationNotice()
|
||||
|
||||
|
||||
}//end class
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ShowSniffDeprecationsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
|
||||
|
||||
<rule ref="TestStandard.DeprecatedInvalid.EmptyDeprecationVersion"/>
|
||||
|
||||
</ruleset>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ShowSniffDeprecationsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
|
||||
|
||||
<rule ref="TestStandard.DeprecatedInvalid.EmptyRemovalVersion"/>
|
||||
|
||||
</ruleset>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ShowSniffDeprecationsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
|
||||
|
||||
<rule ref="TestStandard.DeprecatedInvalid.InvalidDeprecationMessage"/>
|
||||
|
||||
</ruleset>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ShowSniffDeprecationsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
|
||||
|
||||
<rule ref="TestStandard.DeprecatedInvalid.InvalidDeprecationVersion"/>
|
||||
|
||||
</ruleset>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ShowSniffDeprecationsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
|
||||
|
||||
<rule ref="TestStandard.DeprecatedInvalid.InvalidRemovalVersion"/>
|
||||
|
||||
</ruleset>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ShowSniffDeprecationsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
|
||||
|
||||
<!-- This list is non-alphabetic on purpose. The display order is what is being tested. -->
|
||||
<rule ref="TestStandard.Deprecated.WithReplacement"/>
|
||||
<rule ref="TestStandard.Deprecated.WithoutReplacement"/>
|
||||
|
||||
</ruleset>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ShowSniffDeprecationsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
|
||||
|
||||
<rule ref="TestStandard.Deprecated.WithLongReplacement"/>
|
||||
|
||||
</ruleset>
|
||||
+540
@@ -0,0 +1,540 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests PHPCS native handling of sniff deprecations.
|
||||
*
|
||||
* @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 PHP_CodeSniffer\Tests\Core\Ruleset;
|
||||
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Tests\ConfigDouble;
|
||||
use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase;
|
||||
|
||||
/**
|
||||
* Tests PHPCS native handling of sniff deprecations.
|
||||
*
|
||||
* @covers \PHP_CodeSniffer\Ruleset::hasSniffDeprecations
|
||||
* @covers \PHP_CodeSniffer\Ruleset::showSniffDeprecations
|
||||
*/
|
||||
final class ShowSniffDeprecationsTest extends AbstractRulesetTestCase
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test the return value of the hasSniffDeprecations() method.
|
||||
*
|
||||
* @param string $standard The standard to use for the test.
|
||||
* @param bool $expected The expected function return value.
|
||||
*
|
||||
* @dataProvider dataHasSniffDeprecations
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHasSniffDeprecations($standard, $expected)
|
||||
{
|
||||
$config = new ConfigDouble(['.', "--standard=$standard"]);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$this->assertSame($expected, $ruleset->hasSniffDeprecations());
|
||||
|
||||
}//end testHasSniffDeprecations()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testHasSniffDeprecations()
|
||||
*
|
||||
* @return array<string, array<string, string|bool>>
|
||||
*/
|
||||
public static function dataHasSniffDeprecations()
|
||||
{
|
||||
return [
|
||||
'Standard not using deprecated sniffs: PSR1' => [
|
||||
'standard' => 'PSR1',
|
||||
'expected' => false,
|
||||
],
|
||||
'Standard using deprecated sniffs: Test Fixture' => [
|
||||
'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml',
|
||||
'expected' => true,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataHasSniffDeprecations()
|
||||
|
||||
|
||||
/**
|
||||
* Test that the listing with deprecated sniffs will not show when specific command-line options are being used [1].
|
||||
*
|
||||
* @param string $standard The standard to use for the test.
|
||||
* @param array<string> $additionalArgs Optional. Additional arguments to pass.
|
||||
*
|
||||
* @dataProvider dataDeprecatedSniffsListDoesNotShow
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDeprecatedSniffsListDoesNotShow($standard, $additionalArgs=[])
|
||||
{
|
||||
$args = $additionalArgs;
|
||||
$args[] = '.';
|
||||
$args[] = "--standard=$standard";
|
||||
|
||||
$config = new ConfigDouble($args);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$this->expectOutputString('');
|
||||
|
||||
$ruleset->showSniffDeprecations();
|
||||
|
||||
}//end testDeprecatedSniffsListDoesNotShow()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testDeprecatedSniffsListDoesNotShow()
|
||||
*
|
||||
* @return array<string, array<string, string|array<string>>>
|
||||
*/
|
||||
public static function dataDeprecatedSniffsListDoesNotShow()
|
||||
{
|
||||
return [
|
||||
'Standard not using deprecated sniffs: PSR1' => [
|
||||
'standard' => 'PSR1',
|
||||
],
|
||||
'Standard using deprecated sniffs; explain mode' => [
|
||||
'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml',
|
||||
'additionalArgs' => ['-e'],
|
||||
],
|
||||
'Standard using deprecated sniffs; quiet mode' => [
|
||||
'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml',
|
||||
'additionalArgs' => ['-q'],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataDeprecatedSniffsListDoesNotShow()
|
||||
|
||||
|
||||
/**
|
||||
* Test that the listing with deprecated sniffs will not show when specific command-line options are being used [2].
|
||||
*
|
||||
* {@internal Separate test method for the same thing as this test will only work in CS mode.}
|
||||
*
|
||||
* @param string $standard The standard to use for the test.
|
||||
* @param array<string> $additionalArgs Optional. Additional arguments to pass.
|
||||
*
|
||||
* @dataProvider dataDeprecatedSniffsListDoesNotShowNeedsCsMode
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDeprecatedSniffsListDoesNotShowNeedsCsMode($standard, $additionalArgs=[])
|
||||
{
|
||||
if (PHP_CODESNIFFER_CBF === true) {
|
||||
$this->markTestSkipped('This test needs CS mode to run');
|
||||
}
|
||||
|
||||
$this->testDeprecatedSniffsListDoesNotShow($standard, $additionalArgs);
|
||||
|
||||
}//end testDeprecatedSniffsListDoesNotShowNeedsCsMode()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testDeprecatedSniffsListDoesNotShowNeedsCsMode()
|
||||
*
|
||||
* @return array<string, array<string, string|array<string>>>
|
||||
*/
|
||||
public static function dataDeprecatedSniffsListDoesNotShowNeedsCsMode()
|
||||
{
|
||||
return [
|
||||
'Standard using deprecated sniffs; documentation is requested' => [
|
||||
'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml',
|
||||
'additionalArgs' => ['--generator=text'],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataDeprecatedSniffsListDoesNotShowNeedsCsMode()
|
||||
|
||||
|
||||
/**
|
||||
* Test that the listing with deprecated sniffs will not show when using a standard containing deprecated sniffs,
|
||||
* but only running select non-deprecated sniffs (using `--sniffs=...`).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDeprecated()
|
||||
{
|
||||
$standard = __DIR__.'/ShowSniffDeprecationsTest.xml';
|
||||
$config = new ConfigDouble(['.', "--standard=$standard"]);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
/*
|
||||
* Apply sniff restrictions.
|
||||
* For tests we need to manually trigger this if the standard is "installed", like with the fixtures these tests use.
|
||||
*/
|
||||
|
||||
$restrictions = [];
|
||||
$sniffs = [
|
||||
'TestStandard.SetProperty.AllowedAsDeclared',
|
||||
'TestStandard.SetProperty.AllowedViaStdClass',
|
||||
];
|
||||
foreach ($sniffs as $sniffCode) {
|
||||
$parts = explode('.', strtolower($sniffCode));
|
||||
$sniffName = $parts[0].'\\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff';
|
||||
$restrictions[strtolower($sniffName)] = true;
|
||||
}
|
||||
|
||||
$sniffFiles = [];
|
||||
$allSniffs = $ruleset->sniffCodes;
|
||||
foreach ($allSniffs as $sniffName) {
|
||||
$sniffFile = str_replace('\\', DIRECTORY_SEPARATOR, $sniffName);
|
||||
$sniffFile = __DIR__.DIRECTORY_SEPARATOR.$sniffFile.'.php';
|
||||
$sniffFiles[] = $sniffFile;
|
||||
}
|
||||
|
||||
$ruleset->registerSniffs($sniffFiles, $restrictions, []);
|
||||
$ruleset->populateTokenListeners();
|
||||
|
||||
$this->expectOutputString('');
|
||||
|
||||
$ruleset->showSniffDeprecations();
|
||||
|
||||
}//end testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDeprecated()
|
||||
|
||||
|
||||
/**
|
||||
* Test that the listing with deprecated sniffs will not show when using a standard containing deprecated sniffs,
|
||||
* but all deprecated sniffs have been excluded from the run (using `--exclude=...`).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExcluded()
|
||||
{
|
||||
$standard = __DIR__.'/ShowSniffDeprecationsTest.xml';
|
||||
$config = new ConfigDouble(['.', "--standard=$standard"]);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
/*
|
||||
* Apply sniff restrictions.
|
||||
* For tests we need to manually trigger this if the standard is "installed", like with the fixtures these tests use.
|
||||
*/
|
||||
|
||||
$exclusions = [];
|
||||
$exclude = [
|
||||
'TestStandard.Deprecated.WithLongReplacement',
|
||||
'TestStandard.Deprecated.WithoutReplacement',
|
||||
'TestStandard.Deprecated.WithReplacement',
|
||||
'TestStandard.Deprecated.WithReplacementContainingLinuxNewlines',
|
||||
'TestStandard.Deprecated.WithReplacementContainingNewlines',
|
||||
];
|
||||
foreach ($exclude as $sniffCode) {
|
||||
$parts = explode('.', strtolower($sniffCode));
|
||||
$sniffName = $parts[0].'\\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff';
|
||||
$exclusions[strtolower($sniffName)] = true;
|
||||
}
|
||||
|
||||
$sniffFiles = [];
|
||||
$allSniffs = $ruleset->sniffCodes;
|
||||
foreach ($allSniffs as $sniffName) {
|
||||
$sniffFile = str_replace('\\', DIRECTORY_SEPARATOR, $sniffName);
|
||||
$sniffFile = __DIR__.DIRECTORY_SEPARATOR.$sniffFile.'.php';
|
||||
$sniffFiles[] = $sniffFile;
|
||||
}
|
||||
|
||||
$ruleset->registerSniffs($sniffFiles, [], $exclusions);
|
||||
$ruleset->populateTokenListeners();
|
||||
|
||||
$this->expectOutputString('');
|
||||
|
||||
$ruleset->showSniffDeprecations();
|
||||
|
||||
}//end testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExcluded()
|
||||
|
||||
|
||||
/**
|
||||
* Test deprecated sniffs are listed alphabetically in the deprecated sniffs warning.
|
||||
*
|
||||
* This tests a number of different aspects:
|
||||
* 1. That the summary line uses the correct grammar when there is are multiple deprecated sniffs.
|
||||
* 2. That there is no trailing whitespace when the sniff does not provide a custom message.
|
||||
* 3. That custom messages containing new line characters (any type) are handled correctly and
|
||||
* that those new line characters are converted to the OS supported new line char.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDeprecatedSniffsWarning()
|
||||
{
|
||||
$standard = __DIR__.'/ShowSniffDeprecationsTest.xml';
|
||||
$config = new ConfigDouble(["--standard=$standard", '--no-colors']);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 5 deprecated sniffs'.PHP_EOL;
|
||||
$expected .= '--------------------------------------------------------------------------------'.PHP_EOL;
|
||||
$expected .= '- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL;
|
||||
$expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL;
|
||||
$expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL;
|
||||
$expected .= ' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL;
|
||||
$expected .= ' Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In'.PHP_EOL;
|
||||
$expected .= ' lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL;
|
||||
$expected .= ' eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat.'.PHP_EOL;
|
||||
$expected .= ' Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt'.PHP_EOL;
|
||||
$expected .= ' dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum'.PHP_EOL;
|
||||
$expected .= ' semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget'.PHP_EOL;
|
||||
$expected .= ' libero.'.PHP_EOL;
|
||||
$expected .= '- TestStandard.Deprecated.WithoutReplacement'.PHP_EOL;
|
||||
$expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL;
|
||||
$expected .= '- TestStandard.Deprecated.WithReplacement'.PHP_EOL;
|
||||
$expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL;
|
||||
$expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL;
|
||||
$expected .= '- TestStandard.Deprecated.WithReplacementContainingLinuxNewlines'.PHP_EOL;
|
||||
$expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL;
|
||||
$expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL;
|
||||
$expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL;
|
||||
$expected .= ' sed.'.PHP_EOL;
|
||||
$expected .= ' Fusce egestas congue massa semper cursus. Donec quis pretium tellus.'.PHP_EOL;
|
||||
$expected .= ' In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL;
|
||||
$expected .= ' eros sapien at sem.'.PHP_EOL;
|
||||
$expected .= ' Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum'.PHP_EOL;
|
||||
$expected .= ' lectus at egestas.'.PHP_EOL;
|
||||
$expected .= '- TestStandard.Deprecated.WithReplacementContainingNewlines'.PHP_EOL;
|
||||
$expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL;
|
||||
$expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL;
|
||||
$expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL;
|
||||
$expected .= ' sed.'.PHP_EOL;
|
||||
$expected .= ' Fusce egestas congue massa semper cursus. Donec quis pretium tellus.'.PHP_EOL;
|
||||
$expected .= ' In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL;
|
||||
$expected .= ' eros sapien at sem.'.PHP_EOL;
|
||||
$expected .= ' Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum'.PHP_EOL;
|
||||
$expected .= ' lectus at egestas'.PHP_EOL.PHP_EOL;
|
||||
$expected .= 'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL;
|
||||
$expected .= 'future.'.PHP_EOL.PHP_EOL;
|
||||
|
||||
$this->expectOutputString($expected);
|
||||
|
||||
$ruleset->showSniffDeprecations();
|
||||
|
||||
}//end testDeprecatedSniffsWarning()
|
||||
|
||||
|
||||
/**
|
||||
* Test deprecated sniffs are listed alphabetically in the deprecated sniffs warning.
|
||||
*
|
||||
* This tests the following aspects:
|
||||
* 1. That the summary line uses the correct grammar when there is a single deprecated sniff.
|
||||
* 2. That the separator line below the summary maximizes at the longest line length.
|
||||
* 3. That the word wrapping respects the maximum report width.
|
||||
* 4. That the sniff name is truncated if it is longer than the max report width.
|
||||
*
|
||||
* @param int $reportWidth Report width for the test.
|
||||
* @param string $expectedOutput Expected output.
|
||||
*
|
||||
* @dataProvider dataReportWidthIsRespected
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReportWidthIsRespected($reportWidth, $expectedOutput)
|
||||
{
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__.'/ShowSniffDeprecationsReportWidthTest.xml';
|
||||
$config = new ConfigDouble(['.', "--standard=$standard", "--report-width=$reportWidth", '--no-colors']);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$this->expectOutputString($expectedOutput);
|
||||
|
||||
$ruleset->showSniffDeprecations();
|
||||
|
||||
}//end testReportWidthIsRespected()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testReportWidthIsRespected()
|
||||
*
|
||||
* @return array<string, array<string, int|string>>
|
||||
*/
|
||||
public static function dataReportWidthIsRespected()
|
||||
{
|
||||
$summaryLine = 'WARNING: The ShowSniffDeprecationsTest standard uses 1 deprecated sniff'.PHP_EOL;
|
||||
|
||||
// phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important.
|
||||
return [
|
||||
'Report width small: 40; with truncated sniff name and wrapped header and footer lines' => [
|
||||
'reportWidth' => 40,
|
||||
'expectedOutput' => 'WARNING: The ShowSniffDeprecationsTest'.PHP_EOL
|
||||
.'standard uses 1 deprecated sniff'.PHP_EOL
|
||||
.'----------------------------------------'.PHP_EOL
|
||||
.'- TestStandard.Deprecated.WithLongR...'.PHP_EOL
|
||||
.' This sniff has been deprecated since'.PHP_EOL
|
||||
.' v3.8.0 and will be removed in'.PHP_EOL
|
||||
.' v4.0.0. Lorem ipsum dolor sit amet,'.PHP_EOL
|
||||
.' consectetur adipiscing elit. Fusce'.PHP_EOL
|
||||
.' vel vestibulum nunc. Sed luctus'.PHP_EOL
|
||||
.' dolor tortor, eu euismod purus'.PHP_EOL
|
||||
.' pretium sed. Fusce egestas congue'.PHP_EOL
|
||||
.' massa semper cursus. Donec quis'.PHP_EOL
|
||||
.' pretium tellus. In lacinia, augue ut'.PHP_EOL
|
||||
.' ornare porttitor, diam nunc faucibus'.PHP_EOL
|
||||
.' purus, et accumsan eros sapien at'.PHP_EOL
|
||||
.' sem. Sed pulvinar aliquam malesuada.'.PHP_EOL
|
||||
.' Aliquam erat volutpat. Mauris'.PHP_EOL
|
||||
.' gravida rutrum lectus at egestas.'.PHP_EOL
|
||||
.' Fusce tempus elit in tincidunt'.PHP_EOL
|
||||
.' dictum. Suspendisse dictum egestas'.PHP_EOL
|
||||
.' sapien, eget ullamcorper metus'.PHP_EOL
|
||||
.' elementum semper. Vestibulum sem'.PHP_EOL
|
||||
.' justo, consectetur ac tincidunt et,'.PHP_EOL
|
||||
.' finibus eget libero.'.PHP_EOL.PHP_EOL
|
||||
.'Deprecated sniffs are still run, but'.PHP_EOL
|
||||
.'will stop working at some point in the'.PHP_EOL
|
||||
.'future.'.PHP_EOL.PHP_EOL,
|
||||
],
|
||||
'Report width default: 80' => [
|
||||
'reportWidth' => 80,
|
||||
'expectedOutput' => $summaryLine.str_repeat('-', 80).PHP_EOL
|
||||
.'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL
|
||||
.' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL
|
||||
.' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL
|
||||
.' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL
|
||||
.' Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In'.PHP_EOL
|
||||
.' lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL
|
||||
.' eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat.'.PHP_EOL
|
||||
.' Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt'.PHP_EOL
|
||||
.' dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum'.PHP_EOL
|
||||
.' semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget'.PHP_EOL
|
||||
.' libero.'.PHP_EOL.PHP_EOL
|
||||
.'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL
|
||||
.'future.'.PHP_EOL.PHP_EOL,
|
||||
],
|
||||
'Report width matches longest line: 666; the message should not wrap' => [
|
||||
// Length = 4 padding + 75 base line + 587 custom message.
|
||||
'reportWidth' => 666,
|
||||
'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL
|
||||
.'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL
|
||||
.' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. 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.'
|
||||
.PHP_EOL.PHP_EOL
|
||||
.'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL,
|
||||
],
|
||||
'Report width wide: 1000; delimiter line length should match longest line' => [
|
||||
'reportWidth' => 1000,
|
||||
'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL
|
||||
.'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL
|
||||
.' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. 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.'
|
||||
.PHP_EOL.PHP_EOL
|
||||
.'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL,
|
||||
],
|
||||
];
|
||||
// phpcs:enable
|
||||
|
||||
}//end dataReportWidthIsRespected()
|
||||
|
||||
|
||||
/**
|
||||
* Test deprecated sniffs are listed alphabetically in the deprecated sniffs warning.
|
||||
*
|
||||
* Additionally, this test verifies that deprecated sniffs are still registered to run.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDeprecatedSniffsAreListedAlphabetically()
|
||||
{
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__.'/ShowSniffDeprecationsOrderTest.xml';
|
||||
$config = new ConfigDouble(["--standard=$standard", '--no-colors']);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 2 deprecated sniffs'.PHP_EOL;
|
||||
$expected .= '--------------------------------------------------------------------------------'.PHP_EOL;
|
||||
$expected .= '- TestStandard.Deprecated.WithoutReplacement'.PHP_EOL;
|
||||
$expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL;
|
||||
$expected .= '- TestStandard.Deprecated.WithReplacement'.PHP_EOL;
|
||||
$expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL;
|
||||
$expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL.PHP_EOL;
|
||||
$expected .= 'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL;
|
||||
$expected .= 'future.'.PHP_EOL.PHP_EOL;
|
||||
|
||||
$this->expectOutputString($expected);
|
||||
|
||||
$ruleset->showSniffDeprecations();
|
||||
|
||||
// Verify that the sniffs have been registered to run.
|
||||
$this->assertCount(2, $ruleset->sniffCodes, 'Incorrect number of sniff codes registered');
|
||||
$this->assertArrayHasKey(
|
||||
'TestStandard.Deprecated.WithoutReplacement',
|
||||
$ruleset->sniffCodes,
|
||||
'WithoutReplacement sniff not registered'
|
||||
);
|
||||
$this->assertArrayHasKey(
|
||||
'TestStandard.Deprecated.WithReplacement',
|
||||
$ruleset->sniffCodes,
|
||||
'WithReplacement sniff not registered'
|
||||
);
|
||||
|
||||
}//end testDeprecatedSniffsAreListedAlphabetically()
|
||||
|
||||
|
||||
/**
|
||||
* Test that an exception is thrown when any of the interface required methods does not
|
||||
* comply with the return type/value requirements.
|
||||
*
|
||||
* @param string $standard The standard to use for the test.
|
||||
* @param string $exceptionMessage The contents of the expected exception message.
|
||||
*
|
||||
* @dataProvider dataExceptionIsThrownOnIncorrectlyImplementedInterface
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testExceptionIsThrownOnIncorrectlyImplementedInterface($standard, $exceptionMessage)
|
||||
{
|
||||
$this->expectRuntimeExceptionMessage($exceptionMessage);
|
||||
|
||||
// Set up the ruleset.
|
||||
$standard = __DIR__.'/'.$standard;
|
||||
$config = new ConfigDouble(["--standard=$standard"]);
|
||||
$ruleset = new Ruleset($config);
|
||||
|
||||
$ruleset->showSniffDeprecations();
|
||||
|
||||
}//end testExceptionIsThrownOnIncorrectlyImplementedInterface()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testExceptionIsThrownOnIncorrectlyImplementedInterface()
|
||||
*
|
||||
* @return array<string, array<string, string>>
|
||||
*/
|
||||
public static function dataExceptionIsThrownOnIncorrectlyImplementedInterface()
|
||||
{
|
||||
return [
|
||||
'getDeprecationVersion() does not return a string' => [
|
||||
'standard' => 'ShowSniffDeprecationsInvalidDeprecationVersionTest.xml',
|
||||
'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received double',
|
||||
],
|
||||
'getRemovalVersion() does not return a string' => [
|
||||
'standard' => 'ShowSniffDeprecationsInvalidRemovalVersionTest.xml',
|
||||
'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received array',
|
||||
],
|
||||
'getDeprecationMessage() does not return a string' => [
|
||||
'standard' => 'ShowSniffDeprecationsInvalidDeprecationMessageTest.xml',
|
||||
'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidDeprecationMessageSniff::getDeprecationMessage() method must return a string, received object',
|
||||
],
|
||||
'getDeprecationVersion() returns an empty string' => [
|
||||
'standard' => 'ShowSniffDeprecationsEmptyDeprecationVersionTest.xml',
|
||||
'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\EmptyDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received ""',
|
||||
],
|
||||
'getRemovalVersion() returns an empty string' => [
|
||||
'standard' => 'ShowSniffDeprecationsEmptyRemovalVersionTest.xml',
|
||||
'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\EmptyRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received ""',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataExceptionIsThrownOnIncorrectlyImplementedInterface()
|
||||
|
||||
|
||||
}//end class
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ShowSniffDeprecationsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<config name="installed_paths" value="./tests/Core/Ruleset/Fixtures/TestStandard/"/>
|
||||
|
||||
<rule ref="TestStandard">
|
||||
<exclude name="TestStandard.DeprecatedInvalid"/>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* Class to retrieve a filtered file list.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2019 Juliette Reinders Folmer. All rights reserved.
|
||||
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests;
|
||||
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use RegexIterator;
|
||||
|
||||
class FileList
|
||||
{
|
||||
|
||||
/**
|
||||
* The path to the project root directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rootPath;
|
||||
|
||||
/**
|
||||
* Recursive directory iterator.
|
||||
*
|
||||
* @var \DirectoryIterator
|
||||
*/
|
||||
public $fileIterator;
|
||||
|
||||
/**
|
||||
* Base regex to use if no filter regex is provided.
|
||||
*
|
||||
* Matches based on:
|
||||
* - File path starts with the project root (replacement done in constructor).
|
||||
* - Don't match .git/ files.
|
||||
* - Don't match dot files, i.e. "." or "..".
|
||||
* - Don't match backup files.
|
||||
* - Match everything else in a case-insensitive manner.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $baseRegex = '`^%s(?!\.git/)(?!(.*/)?\.+$)(?!.*\.(bak|orig)).*$`Dix';
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $directory The directory to examine.
|
||||
* @param string $rootPath Path to the project root.
|
||||
* @param string $filter PCRE regular expression to filter the file list with.
|
||||
*/
|
||||
public function __construct($directory, $rootPath='', $filter='')
|
||||
{
|
||||
$this->rootPath = $rootPath;
|
||||
|
||||
$directory = new RecursiveDirectoryIterator(
|
||||
$directory,
|
||||
RecursiveDirectoryIterator::UNIX_PATHS
|
||||
);
|
||||
$flattened = new RecursiveIteratorIterator(
|
||||
$directory,
|
||||
RecursiveIteratorIterator::LEAVES_ONLY,
|
||||
RecursiveIteratorIterator::CATCH_GET_CHILD
|
||||
);
|
||||
|
||||
if ($filter === '') {
|
||||
$filter = sprintf($this->baseRegex, preg_quote($this->rootPath));
|
||||
}
|
||||
|
||||
$this->fileIterator = new RegexIterator($flattened, $filter);
|
||||
|
||||
return $this;
|
||||
|
||||
}//end __construct()
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the filtered file list as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
$fileList = [];
|
||||
|
||||
foreach ($this->fileIterator as $file) {
|
||||
$fileList[] = str_replace($this->rootPath, '', $file);
|
||||
}
|
||||
|
||||
return $fileList;
|
||||
|
||||
}//end getList()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+468
@@ -0,0 +1,468 @@
|
||||
<?php
|
||||
/**
|
||||
* An abstract class that all sniff unit tests must extend.
|
||||
*
|
||||
* A sniff unit test checks a .inc file for expected violations of a single
|
||||
* coding standard. Expected errors and warnings that are not found, or
|
||||
* warnings and errors that are not expected, are considered test failures.
|
||||
*
|
||||
* @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 PHP_CodeSniffer\Tests\Standards;
|
||||
|
||||
use DirectoryIterator;
|
||||
use PHP_CodeSniffer\Exceptions\RuntimeException;
|
||||
use PHP_CodeSniffer\Files\LocalFile;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Tests\ConfigDouble;
|
||||
use PHP_CodeSniffer\Util\Common;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
abstract class AbstractSniffUnitTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* Enable or disable the backup and restoration of the $GLOBALS array.
|
||||
* Overwrite this attribute in a child class of TestCase.
|
||||
* Setting this attribute in setUp() has no effect!
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $backupGlobals = false;
|
||||
|
||||
/**
|
||||
* The path to the standard's main directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $standardsDir = null;
|
||||
|
||||
/**
|
||||
* The path to the standard's test directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $testsDir = null;
|
||||
|
||||
|
||||
/**
|
||||
* Sets up this unit test.
|
||||
*
|
||||
* @before
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setUpPrerequisites()
|
||||
{
|
||||
$class = get_class($this);
|
||||
$this->standardsDir = $GLOBALS['PHP_CODESNIFFER_STANDARD_DIRS'][$class];
|
||||
$this->testsDir = $GLOBALS['PHP_CODESNIFFER_TEST_DIRS'][$class];
|
||||
|
||||
}//end setUpPrerequisites()
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of all test files to check.
|
||||
*
|
||||
* These will have the same base as the sniff name but different extensions.
|
||||
* We ignore the .php file as it is the class.
|
||||
*
|
||||
* @param string $testFileBase The base path that the unit tests files will have.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getTestFiles($testFileBase)
|
||||
{
|
||||
$testFiles = [];
|
||||
|
||||
$dir = substr($testFileBase, 0, strrpos($testFileBase, DIRECTORY_SEPARATOR));
|
||||
$di = new DirectoryIterator($dir);
|
||||
|
||||
foreach ($di as $file) {
|
||||
$path = $file->getPathname();
|
||||
if (substr($path, 0, strlen($testFileBase)) === $testFileBase) {
|
||||
if ($path !== $testFileBase.'php' && substr($path, -5) !== 'fixed' && substr($path, -4) !== '.bak') {
|
||||
$testFiles[] = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put them in order.
|
||||
sort($testFiles, SORT_NATURAL);
|
||||
|
||||
return $testFiles;
|
||||
|
||||
}//end getTestFiles()
|
||||
|
||||
|
||||
/**
|
||||
* Should this test be skipped for some reason.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function shouldSkipTest()
|
||||
{
|
||||
return false;
|
||||
|
||||
}//end shouldSkipTest()
|
||||
|
||||
|
||||
/**
|
||||
* Tests the extending classes Sniff class.
|
||||
*
|
||||
* @return void
|
||||
* @throws \PHPUnit\Framework\Exception
|
||||
*/
|
||||
final public function testSniff()
|
||||
{
|
||||
// Skip this test if we can't run in this environment.
|
||||
if ($this->shouldSkipTest() === true) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
$sniffCode = Common::getSniffCode(get_class($this));
|
||||
list($standardName, $categoryName, $sniffName) = explode('.', $sniffCode);
|
||||
|
||||
$testFileBase = $this->testsDir.$categoryName.DIRECTORY_SEPARATOR.$sniffName.'UnitTest.';
|
||||
|
||||
// Get a list of all test files to check.
|
||||
$testFiles = $this->getTestFiles($testFileBase);
|
||||
$GLOBALS['PHP_CODESNIFFER_SNIFF_CASE_FILES'][] = $testFiles;
|
||||
|
||||
if (isset($GLOBALS['PHP_CODESNIFFER_CONFIG']) === true) {
|
||||
$config = $GLOBALS['PHP_CODESNIFFER_CONFIG'];
|
||||
} else {
|
||||
$config = new ConfigDouble();
|
||||
$config->cache = false;
|
||||
$GLOBALS['PHP_CODESNIFFER_CONFIG'] = $config;
|
||||
}
|
||||
|
||||
$config->standards = [$standardName];
|
||||
$config->sniffs = [$sniffCode];
|
||||
$config->ignored = [];
|
||||
|
||||
if (isset($GLOBALS['PHP_CODESNIFFER_RULESETS']) === false) {
|
||||
$GLOBALS['PHP_CODESNIFFER_RULESETS'] = [];
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['PHP_CODESNIFFER_RULESETS'][$standardName]) === false) {
|
||||
$ruleset = new Ruleset($config);
|
||||
$GLOBALS['PHP_CODESNIFFER_RULESETS'][$standardName] = $ruleset;
|
||||
}
|
||||
|
||||
$ruleset = $GLOBALS['PHP_CODESNIFFER_RULESETS'][$standardName];
|
||||
|
||||
$sniffFile = $this->standardsDir.DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR.$categoryName.DIRECTORY_SEPARATOR.$sniffName.'Sniff.php';
|
||||
|
||||
$sniffClassName = substr(get_class($this), 0, -8).'Sniff';
|
||||
$sniffClassName = str_replace('\Tests\\', '\Sniffs\\', $sniffClassName);
|
||||
$sniffClassName = Common::cleanSniffClass($sniffClassName);
|
||||
|
||||
$restrictions = [strtolower($sniffClassName) => true];
|
||||
$ruleset->registerSniffs([$sniffFile], $restrictions, []);
|
||||
$ruleset->populateTokenListeners();
|
||||
|
||||
$failureMessages = [];
|
||||
foreach ($testFiles as $testFile) {
|
||||
$filename = basename($testFile);
|
||||
$oldConfig = $config->getSettings();
|
||||
|
||||
try {
|
||||
$this->setCliValues($filename, $config);
|
||||
$phpcsFile = new LocalFile($testFile, $ruleset, $config);
|
||||
$phpcsFile->process();
|
||||
} catch (RuntimeException $e) {
|
||||
$this->fail('An unexpected exception has been caught: '.$e->getMessage());
|
||||
}
|
||||
|
||||
$failures = $this->generateFailureMessages($phpcsFile);
|
||||
$failureMessages = array_merge($failureMessages, $failures);
|
||||
|
||||
if ($phpcsFile->getFixableCount() > 0) {
|
||||
// Attempt to fix the errors.
|
||||
$phpcsFile->fixer->fixFile();
|
||||
$fixable = $phpcsFile->getFixableCount();
|
||||
if ($fixable > 0) {
|
||||
$failureMessages[] = "Failed to fix $fixable fixable violations in $filename";
|
||||
}
|
||||
|
||||
// Check for a .fixed file to check for accuracy of fixes.
|
||||
$fixedFile = $testFile.'.fixed';
|
||||
$filename = basename($testFile);
|
||||
if (file_exists($fixedFile) === true) {
|
||||
if ($phpcsFile->fixer->getContents() !== file_get_contents($fixedFile)) {
|
||||
// Only generate the (expensive) diff if a difference is expected.
|
||||
$diff = $phpcsFile->fixer->generateDiff($fixedFile);
|
||||
if (trim($diff) !== '') {
|
||||
$fixedFilename = basename($fixedFile);
|
||||
$failureMessages[] = "Fixed version of $filename does not match expected version in $fixedFilename; the diff is\n$diff";
|
||||
}
|
||||
}
|
||||
} else if (is_callable([$this, 'addWarning']) === true) {
|
||||
$this->addWarning("Missing fixed version of $filename to verify the accuracy of fixes, while the sniff is making fixes against the test case file");
|
||||
}
|
||||
}//end if
|
||||
|
||||
// Restore the config.
|
||||
$config->setSettings($oldConfig);
|
||||
}//end foreach
|
||||
|
||||
if (empty($failureMessages) === false) {
|
||||
$this->fail(implode(PHP_EOL, $failureMessages));
|
||||
}
|
||||
|
||||
}//end testSniff()
|
||||
|
||||
|
||||
/**
|
||||
* Generate a list of test failures for a given sniffed file.
|
||||
*
|
||||
* @param \PHP_CodeSniffer\Files\LocalFile $file The file being tested.
|
||||
*
|
||||
* @return array
|
||||
* @throws \PHP_CodeSniffer\Exceptions\RuntimeException
|
||||
*/
|
||||
public function generateFailureMessages(LocalFile $file)
|
||||
{
|
||||
$testFile = $file->getFilename();
|
||||
|
||||
$foundErrors = $file->getErrors();
|
||||
$foundWarnings = $file->getWarnings();
|
||||
$expectedErrors = $this->getErrorList(basename($testFile));
|
||||
$expectedWarnings = $this->getWarningList(basename($testFile));
|
||||
|
||||
if (is_array($expectedErrors) === false) {
|
||||
throw new RuntimeException('getErrorList() must return an array');
|
||||
}
|
||||
|
||||
if (is_array($expectedWarnings) === false) {
|
||||
throw new RuntimeException('getWarningList() must return an array');
|
||||
}
|
||||
|
||||
/*
|
||||
We merge errors and warnings together to make it easier
|
||||
to iterate over them and produce the errors string. In this way,
|
||||
we can report on errors and warnings in the same line even though
|
||||
it's not really structured to allow that.
|
||||
*/
|
||||
|
||||
$allProblems = [];
|
||||
$failureMessages = [];
|
||||
|
||||
foreach ($foundErrors as $line => $lineErrors) {
|
||||
foreach ($lineErrors as $column => $errors) {
|
||||
if (isset($allProblems[$line]) === false) {
|
||||
$allProblems[$line] = [
|
||||
'expected_errors' => 0,
|
||||
'expected_warnings' => 0,
|
||||
'found_errors' => [],
|
||||
'found_warnings' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$foundErrorsTemp = [];
|
||||
foreach ($allProblems[$line]['found_errors'] as $foundError) {
|
||||
$foundErrorsTemp[] = $foundError;
|
||||
}
|
||||
|
||||
$errorsTemp = [];
|
||||
foreach ($errors as $foundError) {
|
||||
$errorsTemp[] = $foundError['message'].' ('.$foundError['source'].')';
|
||||
|
||||
$source = $foundError['source'];
|
||||
if (in_array($source, $GLOBALS['PHP_CODESNIFFER_SNIFF_CODES'], true) === false) {
|
||||
$GLOBALS['PHP_CODESNIFFER_SNIFF_CODES'][] = $source;
|
||||
}
|
||||
|
||||
if ($foundError['fixable'] === true
|
||||
&& in_array($source, $GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES'], true) === false
|
||||
) {
|
||||
$GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES'][] = $source;
|
||||
}
|
||||
}
|
||||
|
||||
$allProblems[$line]['found_errors'] = array_merge($foundErrorsTemp, $errorsTemp);
|
||||
}//end foreach
|
||||
|
||||
if (isset($expectedErrors[$line]) === true) {
|
||||
$allProblems[$line]['expected_errors'] = $expectedErrors[$line];
|
||||
} else {
|
||||
$allProblems[$line]['expected_errors'] = 0;
|
||||
}
|
||||
|
||||
unset($expectedErrors[$line]);
|
||||
}//end foreach
|
||||
|
||||
foreach ($expectedErrors as $line => $numErrors) {
|
||||
if (isset($allProblems[$line]) === false) {
|
||||
$allProblems[$line] = [
|
||||
'expected_errors' => 0,
|
||||
'expected_warnings' => 0,
|
||||
'found_errors' => [],
|
||||
'found_warnings' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$allProblems[$line]['expected_errors'] = $numErrors;
|
||||
}
|
||||
|
||||
foreach ($foundWarnings as $line => $lineWarnings) {
|
||||
foreach ($lineWarnings as $column => $warnings) {
|
||||
if (isset($allProblems[$line]) === false) {
|
||||
$allProblems[$line] = [
|
||||
'expected_errors' => 0,
|
||||
'expected_warnings' => 0,
|
||||
'found_errors' => [],
|
||||
'found_warnings' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$foundWarningsTemp = [];
|
||||
foreach ($allProblems[$line]['found_warnings'] as $foundWarning) {
|
||||
$foundWarningsTemp[] = $foundWarning;
|
||||
}
|
||||
|
||||
$warningsTemp = [];
|
||||
foreach ($warnings as $warning) {
|
||||
$warningsTemp[] = $warning['message'].' ('.$warning['source'].')';
|
||||
|
||||
$source = $warning['source'];
|
||||
if (in_array($source, $GLOBALS['PHP_CODESNIFFER_SNIFF_CODES'], true) === false) {
|
||||
$GLOBALS['PHP_CODESNIFFER_SNIFF_CODES'][] = $source;
|
||||
}
|
||||
|
||||
if ($warning['fixable'] === true
|
||||
&& in_array($source, $GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES'], true) === false
|
||||
) {
|
||||
$GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES'][] = $source;
|
||||
}
|
||||
}
|
||||
|
||||
$allProblems[$line]['found_warnings'] = array_merge($foundWarningsTemp, $warningsTemp);
|
||||
}//end foreach
|
||||
|
||||
if (isset($expectedWarnings[$line]) === true) {
|
||||
$allProblems[$line]['expected_warnings'] = $expectedWarnings[$line];
|
||||
} else {
|
||||
$allProblems[$line]['expected_warnings'] = 0;
|
||||
}
|
||||
|
||||
unset($expectedWarnings[$line]);
|
||||
}//end foreach
|
||||
|
||||
foreach ($expectedWarnings as $line => $numWarnings) {
|
||||
if (isset($allProblems[$line]) === false) {
|
||||
$allProblems[$line] = [
|
||||
'expected_errors' => 0,
|
||||
'expected_warnings' => 0,
|
||||
'found_errors' => [],
|
||||
'found_warnings' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$allProblems[$line]['expected_warnings'] = $numWarnings;
|
||||
}
|
||||
|
||||
// Order the messages by line number.
|
||||
ksort($allProblems);
|
||||
|
||||
foreach ($allProblems as $line => $problems) {
|
||||
$numErrors = count($problems['found_errors']);
|
||||
$numWarnings = count($problems['found_warnings']);
|
||||
$expectedErrors = $problems['expected_errors'];
|
||||
$expectedWarnings = $problems['expected_warnings'];
|
||||
|
||||
$errors = '';
|
||||
$foundString = '';
|
||||
|
||||
if ($expectedErrors !== $numErrors || $expectedWarnings !== $numWarnings) {
|
||||
$lineMessage = "[LINE $line]";
|
||||
$expectedMessage = 'Expected ';
|
||||
$foundMessage = 'in '.basename($testFile).' but found ';
|
||||
|
||||
if ($expectedErrors !== $numErrors) {
|
||||
$expectedMessage .= "$expectedErrors error(s)";
|
||||
$foundMessage .= "$numErrors error(s)";
|
||||
if ($numErrors !== 0) {
|
||||
$foundString .= 'error(s)';
|
||||
$errors .= implode(PHP_EOL.' -> ', $problems['found_errors']);
|
||||
}
|
||||
|
||||
if ($expectedWarnings !== $numWarnings) {
|
||||
$expectedMessage .= ' and ';
|
||||
$foundMessage .= ' and ';
|
||||
if ($numWarnings !== 0) {
|
||||
if ($foundString !== '') {
|
||||
$foundString .= ' and ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($expectedWarnings !== $numWarnings) {
|
||||
$expectedMessage .= "$expectedWarnings warning(s)";
|
||||
$foundMessage .= "$numWarnings warning(s)";
|
||||
if ($numWarnings !== 0) {
|
||||
$foundString .= 'warning(s)';
|
||||
if (empty($errors) === false) {
|
||||
$errors .= PHP_EOL.' -> ';
|
||||
}
|
||||
|
||||
$errors .= implode(PHP_EOL.' -> ', $problems['found_warnings']);
|
||||
}
|
||||
}
|
||||
|
||||
$fullMessage = "$lineMessage $expectedMessage $foundMessage.";
|
||||
if ($errors !== '') {
|
||||
$fullMessage .= " The $foundString found were:".PHP_EOL." -> $errors";
|
||||
}
|
||||
|
||||
$failureMessages[] = $fullMessage;
|
||||
}//end if
|
||||
}//end foreach
|
||||
|
||||
return $failureMessages;
|
||||
|
||||
}//end generateFailureMessages()
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of CLI values to set before the file is tested.
|
||||
*
|
||||
* @param string $filename The name of the file being tested.
|
||||
* @param \PHP_CodeSniffer\Config $config The config data for the run.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setCliValues($filename, $config)
|
||||
{
|
||||
|
||||
}//end setCliValues()
|
||||
|
||||
|
||||
/**
|
||||
* Returns the lines where errors should occur.
|
||||
*
|
||||
* The key of the array should represent the line number and the value
|
||||
* should represent the number of errors that should occur on that line.
|
||||
*
|
||||
* @return array<int, int>
|
||||
*/
|
||||
abstract protected function getErrorList();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the lines where warnings should occur.
|
||||
*
|
||||
* The key of the array should represent the line number and the value
|
||||
* should represent the number of warnings that should occur on that line.
|
||||
*
|
||||
* @return array<int, int>
|
||||
*/
|
||||
abstract protected function getWarningList();
|
||||
|
||||
|
||||
}//end class
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* A test class for testing all sniffs for installed standards.
|
||||
*
|
||||
* @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 PHP_CodeSniffer\Tests\Standards;
|
||||
|
||||
use PHP_CodeSniffer\Autoload;
|
||||
use PHP_CodeSniffer\Util\Standards;
|
||||
use PHPUnit\Framework\TestSuite;
|
||||
use PHPUnit\TextUI\TestRunner;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
class AllSniffs
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the test runner.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function main()
|
||||
{
|
||||
TestRunner::run(self::suite());
|
||||
|
||||
}//end main()
|
||||
|
||||
|
||||
/**
|
||||
* Add all sniff unit tests into a test suite.
|
||||
*
|
||||
* Sniff unit tests are found by recursing through the 'Tests' directory
|
||||
* of each installed coding standard.
|
||||
*
|
||||
* @return \PHPUnit\Framework\TestSuite
|
||||
*/
|
||||
public static function suite()
|
||||
{
|
||||
$GLOBALS['PHP_CODESNIFFER_SNIFF_CODES'] = [];
|
||||
$GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES'] = [];
|
||||
$GLOBALS['PHP_CODESNIFFER_SNIFF_CASE_FILES'] = [];
|
||||
|
||||
$suite = new TestSuite('PHP CodeSniffer Standards');
|
||||
|
||||
// Optionally allow for ignoring the tests for one or more standards.
|
||||
$ignoreTestsForStandards = getenv('PHPCS_IGNORE_TESTS');
|
||||
if ($ignoreTestsForStandards === false) {
|
||||
$ignoreTestsForStandards = [];
|
||||
} else {
|
||||
$ignoreTestsForStandards = explode(',', $ignoreTestsForStandards);
|
||||
}
|
||||
|
||||
$installedStandards = self::getInstalledStandardDetails();
|
||||
|
||||
foreach ($installedStandards as $standard => $details) {
|
||||
Autoload::addSearchPath($details['path'], $details['namespace']);
|
||||
|
||||
if (in_array($standard, $ignoreTestsForStandards, true) === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$testsDir = $details['path'].DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR;
|
||||
if (is_dir($testsDir) === false) {
|
||||
// No tests for this standard.
|
||||
continue;
|
||||
}
|
||||
|
||||
$di = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($testsDir));
|
||||
|
||||
foreach ($di as $file) {
|
||||
// Skip hidden files.
|
||||
if (substr($file->getFilename(), 0, 1) === '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Tests must have the extension 'php'.
|
||||
$parts = explode('.', $file);
|
||||
$ext = array_pop($parts);
|
||||
if ($ext !== 'php') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$className = Autoload::loadFile($file->getPathname());
|
||||
$GLOBALS['PHP_CODESNIFFER_STANDARD_DIRS'][$className] = $details['path'];
|
||||
$GLOBALS['PHP_CODESNIFFER_TEST_DIRS'][$className] = $testsDir;
|
||||
$suite->addTestSuite($className);
|
||||
}
|
||||
}//end foreach
|
||||
|
||||
return $suite;
|
||||
|
||||
}//end suite()
|
||||
|
||||
|
||||
/**
|
||||
* Get the details of all coding standards installed.
|
||||
*
|
||||
* @return array
|
||||
* @see Standards::getInstalledStandardDetails()
|
||||
*/
|
||||
protected static function getInstalledStandardDetails()
|
||||
{
|
||||
return Standards::getInstalledStandardDetails(true);
|
||||
|
||||
}//end getInstalledStandardDetails()
|
||||
|
||||
|
||||
}//end class
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* A PHP_CodeSniffer specific test suite for PHPUnit.
|
||||
*
|
||||
* @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 PHP_CodeSniffer\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestResult;
|
||||
use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite;
|
||||
|
||||
class TestSuite extends PHPUnit_TestSuite
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Runs the tests and collects their result in a TestResult.
|
||||
*
|
||||
* @param \PHPUnit\Framework\TestResult $result A test result.
|
||||
*
|
||||
* @return \PHPUnit\Framework\TestResult
|
||||
*/
|
||||
public function run(TestResult $result=null)
|
||||
{
|
||||
$result = parent::run($result);
|
||||
printPHPCodeSnifferTestOutput();
|
||||
return $result;
|
||||
|
||||
}//end run()
|
||||
|
||||
|
||||
}//end class
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* A PHP_CodeSniffer specific test suite for PHPUnit.
|
||||
*
|
||||
* @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 PHP_CodeSniffer\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestResult;
|
||||
use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite;
|
||||
|
||||
class TestSuite extends PHPUnit_TestSuite
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Runs the tests and collects their result in a TestResult.
|
||||
*
|
||||
* @param \PHPUnit\Framework\TestResult|null $result A test result.
|
||||
*
|
||||
* @return \PHPUnit\Framework\TestResult
|
||||
*/
|
||||
public function run(?TestResult $result=null): TestResult
|
||||
{
|
||||
$result = parent::run($result);
|
||||
printPHPCodeSnifferTestOutput();
|
||||
return $result;
|
||||
|
||||
}//end run()
|
||||
|
||||
|
||||
}//end class
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* Bootstrap file for PHP_CodeSniffer unit tests.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2017 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
if (defined('PHP_CODESNIFFER_IN_TESTS') === false) {
|
||||
define('PHP_CODESNIFFER_IN_TESTS', true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the test suite should be run in CBF mode.
|
||||
*
|
||||
* Use `<php><env name="PHP_CODESNIFFER_CBF" value="1"/></php>` in a `phpunit.xml` file
|
||||
* or set the ENV variable at an OS-level to enable CBF mode.
|
||||
*
|
||||
* To run the CBF specific tests, use the following command:
|
||||
* vendor/bin/phpunit --group CBF --exclude-group nothing
|
||||
*
|
||||
* If the ENV variable has not been set, or is set to "false", the tests will run in CS mode.
|
||||
*/
|
||||
|
||||
if (defined('PHP_CODESNIFFER_CBF') === false) {
|
||||
$cbfMode = getenv('PHP_CODESNIFFER_CBF');
|
||||
if ($cbfMode === '1') {
|
||||
define('PHP_CODESNIFFER_CBF', true);
|
||||
echo 'Note: Tests are running in "CBF" mode'.PHP_EOL.PHP_EOL;
|
||||
} else {
|
||||
define('PHP_CODESNIFFER_CBF', false);
|
||||
echo 'Note: Tests are running in "CS" mode'.PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (defined('PHP_CODESNIFFER_VERBOSITY') === false) {
|
||||
define('PHP_CODESNIFFER_VERBOSITY', 0);
|
||||
}
|
||||
|
||||
require_once __DIR__.'/../autoload.php';
|
||||
|
||||
$tokens = new \PHP_CodeSniffer\Util\Tokens();
|
||||
|
||||
// Compatibility for PHPUnit < 6 and PHPUnit 6+.
|
||||
if (class_exists('PHPUnit_Framework_TestSuite') === true && class_exists('PHPUnit\Framework\TestSuite') === false) {
|
||||
class_alias('PHPUnit_Framework_TestSuite', 'PHPUnit'.'\Framework\TestSuite');
|
||||
}
|
||||
|
||||
if (class_exists('PHPUnit_Framework_TestCase') === true && class_exists('PHPUnit\Framework\TestCase') === false) {
|
||||
class_alias('PHPUnit_Framework_TestCase', 'PHPUnit'.'\Framework\TestCase');
|
||||
}
|
||||
|
||||
if (class_exists('PHPUnit_TextUI_TestRunner') === true && class_exists('PHPUnit\TextUI\TestRunner') === false) {
|
||||
class_alias('PHPUnit_TextUI_TestRunner', 'PHPUnit'.'\TextUI\TestRunner');
|
||||
}
|
||||
|
||||
if (class_exists('PHPUnit_Framework_TestResult') === true && class_exists('PHPUnit\Framework\TestResult') === false) {
|
||||
class_alias('PHPUnit_Framework_TestResult', 'PHPUnit'.'\Framework\TestResult');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A global util function to help print unit test fixing data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function printPHPCodeSnifferTestOutput()
|
||||
{
|
||||
echo PHP_EOL.PHP_EOL;
|
||||
|
||||
$output = 'The test files';
|
||||
$data = [];
|
||||
|
||||
$codeCount = count($GLOBALS['PHP_CODESNIFFER_SNIFF_CODES']);
|
||||
if (empty($GLOBALS['PHP_CODESNIFFER_SNIFF_CASE_FILES']) === false) {
|
||||
$files = call_user_func_array('array_merge', $GLOBALS['PHP_CODESNIFFER_SNIFF_CASE_FILES']);
|
||||
$files = array_unique($files);
|
||||
$fileCount = count($files);
|
||||
|
||||
$output = '%d sniff test files';
|
||||
$data[] = $fileCount;
|
||||
}
|
||||
|
||||
$output .= ' generated %d unique error codes';
|
||||
$data[] = $codeCount;
|
||||
|
||||
if ($codeCount > 0) {
|
||||
$fixes = count($GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES']);
|
||||
$percent = round(($fixes / $codeCount * 100), 2);
|
||||
|
||||
$output .= '; %d were fixable (%d%%)';
|
||||
$data[] = $fixes;
|
||||
$data[] = $percent;
|
||||
}
|
||||
|
||||
vprintf($output, $data);
|
||||
|
||||
}//end printPHPCodeSnifferTestOutput()
|
||||
Reference in New Issue
Block a user