implement JS password scoring, td_stock approve logicc
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* A test class for running all PHP_CodeSniffer unit tests.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests;
|
||||
|
||||
if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === false) {
|
||||
include_once 'Core/AllTests.php';
|
||||
include_once 'Standards/AllSniffs.php';
|
||||
} else {
|
||||
include_once 'CodeSniffer/Core/AllTests.php';
|
||||
include_once 'CodeSniffer/Standards/AllSniffs.php';
|
||||
include_once 'FileList.php';
|
||||
}
|
||||
|
||||
// PHPUnit 7 made the TestSuite run() method incompatible with
|
||||
// older PHPUnit versions due to return type hints, so maintain
|
||||
// two different suite objects.
|
||||
$phpunit7 = false;
|
||||
if (class_exists('\PHPUnit\Runner\Version') === true) {
|
||||
$version = \PHPUnit\Runner\Version::id();
|
||||
if ($version[0] === '7') {
|
||||
$phpunit7 = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($phpunit7 === true) {
|
||||
include_once 'TestSuite7.php';
|
||||
} else {
|
||||
include_once 'TestSuite.php';
|
||||
}
|
||||
|
||||
class PHP_CodeSniffer_AllTests
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Add all PHP_CodeSniffer test suites into a single test suite.
|
||||
*
|
||||
* @return \PHPUnit\Framework\TestSuite
|
||||
*/
|
||||
public static function suite()
|
||||
{
|
||||
$GLOBALS['PHP_CODESNIFFER_STANDARD_DIRS'] = [];
|
||||
$GLOBALS['PHP_CODESNIFFER_TEST_DIRS'] = [];
|
||||
|
||||
// Use a special PHP_CodeSniffer test suite so that we can
|
||||
// unset our autoload function after the run.
|
||||
$suite = new TestSuite('PHP CodeSniffer');
|
||||
|
||||
$suite->addTest(Core\AllTests::suite());
|
||||
$suite->addTest(Standards\AllSniffs::suite());
|
||||
|
||||
return $suite;
|
||||
|
||||
}//end suite()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+140
@@ -0,0 +1,140 @@
|
||||
<?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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core;
|
||||
|
||||
use PHP_CodeSniffer\Config;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Files\DummyFile;
|
||||
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 \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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
$config = new Config();
|
||||
$config->standards = ['PSR1'];
|
||||
|
||||
$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->process();
|
||||
|
||||
}//end setUpBeforeClass()
|
||||
|
||||
|
||||
/**
|
||||
* Clean up after finished test.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function tearDownAfterClass()
|
||||
{
|
||||
self::$phpcsFile = null;
|
||||
|
||||
}//end tearDownAfterClass()
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$start = (self::$phpcsFile->numTokens - 1);
|
||||
$comment = self::$phpcsFile->findPrevious(
|
||||
T_COMMENT,
|
||||
$start,
|
||||
null,
|
||||
false,
|
||||
$commentString
|
||||
);
|
||||
|
||||
$tokens = self::$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 = self::$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;
|
||||
}
|
||||
|
||||
$this->assertFalse(true, $msg);
|
||||
}
|
||||
|
||||
return $target;
|
||||
|
||||
}//end getTargetToken()
|
||||
|
||||
|
||||
}//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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core;
|
||||
|
||||
use PHP_CodeSniffer\Tests\FileList;
|
||||
use PHPUnit\TextUI\TestRunner;
|
||||
use PHPUnit\Framework\TestSuite;
|
||||
|
||||
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
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Autoload::determineLoadedClass method.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
|
||||
|
||||
use PHP_CodeSniffer\Autoload;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class DetermineLoadedClassTest extends TestCase
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Load the test files.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
include __DIR__.'/TestFiles/Sub/C.inc';
|
||||
|
||||
}//end setUpBeforeClass()
|
||||
|
||||
|
||||
/**
|
||||
* Test for when class list is ordered.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testOrdered()
|
||||
{
|
||||
$classesBeforeLoad = [
|
||||
'classes' => [],
|
||||
'interfaces' => [],
|
||||
'traits' => [],
|
||||
];
|
||||
|
||||
$classesAfterLoad = [
|
||||
'classes' => [
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\A',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\B',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\C',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C',
|
||||
],
|
||||
'interfaces' => [],
|
||||
'traits' => [],
|
||||
];
|
||||
|
||||
$className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad);
|
||||
$this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className);
|
||||
|
||||
}//end testOrdered()
|
||||
|
||||
|
||||
/**
|
||||
* Test for when class list is out of order.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUnordered()
|
||||
{
|
||||
$classesBeforeLoad = [
|
||||
'classes' => [],
|
||||
'interfaces' => [],
|
||||
'traits' => [],
|
||||
];
|
||||
|
||||
$classesAfterLoad = [
|
||||
'classes' => [
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\A',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\C',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\B',
|
||||
],
|
||||
'interfaces' => [],
|
||||
'traits' => [],
|
||||
];
|
||||
|
||||
$className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad);
|
||||
$this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className);
|
||||
|
||||
$classesAfterLoad = [
|
||||
'classes' => [
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\A',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\C',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\B',
|
||||
],
|
||||
'interfaces' => [],
|
||||
'traits' => [],
|
||||
];
|
||||
|
||||
$className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad);
|
||||
$this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className);
|
||||
|
||||
$classesAfterLoad = [
|
||||
'classes' => [
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\A',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\C',
|
||||
'PHP_CodeSniffer\Tests\Core\Autoloader\B',
|
||||
],
|
||||
'interfaces' => [],
|
||||
'traits' => [],
|
||||
];
|
||||
|
||||
$className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad);
|
||||
$this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className);
|
||||
|
||||
}//end testUnordered()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
|
||||
class A {}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
|
||||
require 'A.inc';
|
||||
class B extends A {}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
|
||||
require 'B.inc';
|
||||
class C extends B {}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
namespace PHP_CodeSniffer\Tests\Core\Autoloader\Sub;
|
||||
require __DIR__.'/../C.inc';
|
||||
use PHP_CodeSniffer\Tests\Core\Autoloader\C as ParentC;
|
||||
class C extends ParentC {}
|
||||
+1247
File diff suppressed because it is too large
Load Diff
Vendored
+105
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/* testSimpleAssignment */
|
||||
$a = false;
|
||||
|
||||
/* testControlStructure */
|
||||
while(true) {}
|
||||
$a = 1;
|
||||
|
||||
/* testClosureAssignment */
|
||||
$a = function($b=false;){};
|
||||
|
||||
/* testHeredocFunctionArg */
|
||||
myFunction(<<<END
|
||||
Foo
|
||||
END
|
||||
, 'bar');
|
||||
|
||||
/* testSwitch */
|
||||
switch ($a) {
|
||||
case 1: {break;}
|
||||
default: {break;}
|
||||
}
|
||||
|
||||
/* testStatementAsArrayValue */
|
||||
$a = [new Datetime];
|
||||
$a = array(new Datetime);
|
||||
$a = new Datetime;
|
||||
|
||||
/* testUseGroup */
|
||||
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
|
||||
|
||||
$a = [
|
||||
/* testArrowFunctionArrayValue */
|
||||
'a' => fn() => return 1,
|
||||
'b' => fn() => return 1,
|
||||
];
|
||||
|
||||
/* testStaticArrowFunction */
|
||||
static fn ($a) => $a;
|
||||
|
||||
return 0;
|
||||
|
||||
/* testArrowFunctionReturnValue */
|
||||
fn(): array => [a($a, $b)];
|
||||
|
||||
/* testArrowFunctionAsArgument */
|
||||
$foo = foo(
|
||||
fn() => bar()
|
||||
);
|
||||
|
||||
/* testArrowFunctionWithArrayAsArgument */
|
||||
$foo = foo(
|
||||
fn() => [$row[0], $row[3]]
|
||||
);
|
||||
|
||||
$match = match ($a) {
|
||||
/* testMatchCase */
|
||||
1 => 'foo',
|
||||
/* testMatchDefault */
|
||||
default => 'bar'
|
||||
};
|
||||
|
||||
$match = match ($a) {
|
||||
/* testMatchMultipleCase */
|
||||
1, 2, => $a * $b,
|
||||
/* testMatchDefaultComma */
|
||||
default, => 'something'
|
||||
};
|
||||
|
||||
match ($pressedKey) {
|
||||
/* testMatchFunctionCall */
|
||||
Key::RETURN_ => save($value, $user)
|
||||
};
|
||||
|
||||
$result = match (true) {
|
||||
/* testMatchFunctionCallArm */
|
||||
str_contains($text, 'Welcome') || str_contains($text, 'Hello') => 'en',
|
||||
str_contains($text, 'Bienvenue') || str_contains($text, 'Bonjour') => 'fr',
|
||||
default => 'pl'
|
||||
};
|
||||
|
||||
/* testMatchClosure */
|
||||
$result = match ($key) {
|
||||
1 => function($a, $b) {},
|
||||
2 => function($b, $c) {},
|
||||
};
|
||||
|
||||
/* testMatchArray */
|
||||
$result = match ($key) {
|
||||
1 => [1,2,3],
|
||||
2 => [1 => one(), 2 => two()],
|
||||
};
|
||||
|
||||
/* testNestedMatch */
|
||||
$result = match ($key) {
|
||||
1 => match ($key) {
|
||||
1 => 'one',
|
||||
2 => 'two',
|
||||
},
|
||||
2 => match ($key) {
|
||||
1 => 'two',
|
||||
2 => 'one',
|
||||
},
|
||||
};
|
||||
Vendored
+415
@@ -0,0 +1,415 @@
|
||||
<?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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class FindEndOfStatementTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test a simple assignment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSimpleAssignment()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testSimpleAssignment */', T_VARIABLE);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 5), $found);
|
||||
|
||||
}//end testSimpleAssignment()
|
||||
|
||||
|
||||
/**
|
||||
* Test a direct call to a control structure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testControlStructure()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testControlStructure */', T_WHILE);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 6), $found);
|
||||
|
||||
}//end testControlStructure()
|
||||
|
||||
|
||||
/**
|
||||
* Test the assignment of a closure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testClosureAssignment()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testClosureAssignment */', T_VARIABLE, '$a');
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 13), $found);
|
||||
|
||||
}//end testClosureAssignment()
|
||||
|
||||
|
||||
/**
|
||||
* Test using a heredoc in a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredocFunctionArg()
|
||||
{
|
||||
// Find the end of the function.
|
||||
$start = $this->getTargetToken('/* testHeredocFunctionArg */', T_STRING, 'myFunction');
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 10), $found);
|
||||
|
||||
// Find the end of the heredoc.
|
||||
$start += 2;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 4), $found);
|
||||
|
||||
// Find the end of the last arg.
|
||||
$start = ($found + 2);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testHeredocFunctionArg()
|
||||
|
||||
|
||||
/**
|
||||
* Test parts of a switch statement.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSwitch()
|
||||
{
|
||||
// Find the end of the switch.
|
||||
$start = $this->getTargetToken('/* testSwitch */', T_SWITCH);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 28), $found);
|
||||
|
||||
// Find the end of the case.
|
||||
$start += 9;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 8), $found);
|
||||
|
||||
// Find the end of default case.
|
||||
$start += 11;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 6), $found);
|
||||
|
||||
}//end testSwitch()
|
||||
|
||||
|
||||
/**
|
||||
* Test statements that are array values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStatementAsArrayValue()
|
||||
{
|
||||
// Test short array syntax.
|
||||
$start = $this->getTargetToken('/* testStatementAsArrayValue */', T_NEW);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 2), $found);
|
||||
|
||||
// Test long array syntax.
|
||||
$start += 12;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 2), $found);
|
||||
|
||||
// Test same statement outside of array.
|
||||
$start += 10;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 3), $found);
|
||||
|
||||
}//end testStatementAsArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test a use group.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUseGroup()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testUseGroup */', T_USE);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 23), $found);
|
||||
|
||||
}//end testUseGroup()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function as array value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionArrayValue()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_FN);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 9), $found);
|
||||
|
||||
}//end testArrowFunctionArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test static arrow function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStaticArrowFunction()
|
||||
{
|
||||
$static = $this->getTargetToken('/* testStaticArrowFunction */', T_STATIC);
|
||||
$fn = $this->getTargetToken('/* testStaticArrowFunction */', T_FN);
|
||||
|
||||
$endOfStatementStatic = self::$phpcsFile->findEndOfStatement($static);
|
||||
$endOfStatementFn = self::$phpcsFile->findEndOfStatement($fn);
|
||||
|
||||
$this->assertSame($endOfStatementFn, $endOfStatementStatic);
|
||||
|
||||
}//end testStaticArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with return value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionReturnValue()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionReturnValue */', T_FN);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 18), $found);
|
||||
|
||||
}//end testArrowFunctionReturnValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function used as a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionAsArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionAsArgument */', T_FN);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 8), $found);
|
||||
|
||||
}//end testArrowFunctionAsArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with arrays used as a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionWithArrayAsArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionWithArrayAsArgument */', T_FN);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 17), $found);
|
||||
|
||||
}//end testArrowFunctionWithArrayAsArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test simple match expression case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchCase()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchCase */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 5), $found);
|
||||
|
||||
$start = $this->getTargetToken('/* testMatchCase */', T_CONSTANT_ENCAPSED_STRING);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 1), $found);
|
||||
|
||||
}//end testMatchCase()
|
||||
|
||||
|
||||
/**
|
||||
* Test simple match expression default case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchDefault()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchDefault */', T_MATCH_DEFAULT);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 4), $found);
|
||||
|
||||
$start = $this->getTargetToken('/* testMatchDefault */', T_CONSTANT_ENCAPSED_STRING);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testMatchDefault()
|
||||
|
||||
|
||||
/**
|
||||
* Test multiple comma-separated match expression case values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchMultipleCase()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchMultipleCase */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
$this->assertSame(($start + 13), $found);
|
||||
|
||||
$start += 6;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
$this->assertSame(($start + 7), $found);
|
||||
|
||||
}//end testMatchMultipleCase()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression default case with trailing comma.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchDefaultComma()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchDefaultComma */', T_MATCH_DEFAULT);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 5), $found);
|
||||
|
||||
}//end testMatchDefaultComma()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with function call.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchFunctionCall()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchFunctionCall */', T_STRING);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 12), $found);
|
||||
|
||||
$start += 8;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 1), $found);
|
||||
|
||||
}//end testMatchFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with function call in the arm.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchFunctionCallArm()
|
||||
{
|
||||
// Check the first case.
|
||||
$start = $this->getTargetToken('/* testMatchFunctionCallArm */', T_STRING);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 21), $found);
|
||||
|
||||
// Check the second case.
|
||||
$start += 24;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 21), $found);
|
||||
|
||||
}//end testMatchFunctionCallArm()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with closure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchClosure()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchClosure */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 14), $found);
|
||||
|
||||
$start += 17;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 14), $found);
|
||||
|
||||
}//end testMatchClosure()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with array declaration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchArray()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchArray */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 11), $found);
|
||||
|
||||
$start += 14;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 22), $found);
|
||||
|
||||
}//end testMatchArray()
|
||||
|
||||
|
||||
/**
|
||||
* Test nested match expressions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedMatch()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testNestedMatch */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 30), $found);
|
||||
|
||||
$start += 21;
|
||||
$found = self::$phpcsFile->findEndOfStatement($start);
|
||||
|
||||
$this->assertSame(($start + 5), $found);
|
||||
|
||||
}//end testNestedMatch()
|
||||
|
||||
|
||||
}//end class
|
||||
lib/zxcvbn-php-master/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
class testFECNClass {}
|
||||
|
||||
/* testExtendedClass */
|
||||
class testFECNExtendedClass extends testFECNClass {}
|
||||
|
||||
/* testNamespacedClass */
|
||||
class testFECNNamespacedClass extends \PHP_CodeSniffer\Tests\Core\File\testFECNClass {}
|
||||
|
||||
/* testNonExtendedClass */
|
||||
class testFECNNonExtendedClass {}
|
||||
|
||||
/* testInterface */
|
||||
interface testFECNInterface {}
|
||||
|
||||
/* testInterfaceThatExtendsInterface */
|
||||
interface testInterfaceThatExtendsInterface extends testFECNInterface{}
|
||||
|
||||
/* testInterfaceThatExtendsFQCNInterface */
|
||||
interface testInterfaceThatExtendsFQCNInterface extends \PHP_CodeSniffer\Tests\Core\File\testFECNInterface{}
|
||||
|
||||
/* testNestedExtendedClass */
|
||||
class testFECNNestedExtendedClass {
|
||||
public function someMethod() {
|
||||
/* testNestedExtendedAnonClass */
|
||||
$anon = new class extends testFECNAnonClass {};
|
||||
}
|
||||
}
|
||||
|
||||
/* testClassThatExtendsAndImplements */
|
||||
class testFECNClassThatExtendsAndImplements extends testFECNClass implements InterfaceA, InterfaceB {}
|
||||
|
||||
/* testClassThatImplementsAndExtends */
|
||||
class testFECNClassThatImplementsAndExtends implements InterfaceA, InterfaceB extends testFECNClass {}
|
||||
lib/zxcvbn-php-master/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.php
Vendored
+93
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File:findExtendedClassName method.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class FindExtendedClassNameTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test retrieving the name of the class being extended by another class
|
||||
* (or interface).
|
||||
*
|
||||
* @param string $identifier Comment which precedes the test case.
|
||||
* @param bool $expected Expected function output.
|
||||
*
|
||||
* @dataProvider dataExtendedClass
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFindExtendedClassName($identifier, $expected)
|
||||
{
|
||||
$OOToken = $this->getTargetToken($identifier, [T_CLASS, T_ANON_CLASS, T_INTERFACE]);
|
||||
$result = self::$phpcsFile->findExtendedClassName($OOToken);
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
}//end testFindExtendedClassName()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider for the FindExtendedClassName test.
|
||||
*
|
||||
* @see testFindExtendedClassName()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataExtendedClass()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testExtendedClass */',
|
||||
'testFECNClass',
|
||||
],
|
||||
[
|
||||
'/* testNamespacedClass */',
|
||||
'\PHP_CodeSniffer\Tests\Core\File\testFECNClass',
|
||||
],
|
||||
[
|
||||
'/* testNonExtendedClass */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testInterface */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testInterfaceThatExtendsInterface */',
|
||||
'testFECNInterface',
|
||||
],
|
||||
[
|
||||
'/* testInterfaceThatExtendsFQCNInterface */',
|
||||
'\PHP_CodeSniffer\Tests\Core\File\testFECNInterface',
|
||||
],
|
||||
[
|
||||
'/* testNestedExtendedClass */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testNestedExtendedAnonClass */',
|
||||
'testFECNAnonClass',
|
||||
],
|
||||
[
|
||||
'/* testClassThatExtendsAndImplements */',
|
||||
'testFECNClass',
|
||||
],
|
||||
[
|
||||
'/* testClassThatImplementsAndExtends */',
|
||||
'testFECNClass',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataExtendedClass()
|
||||
|
||||
|
||||
}//end class
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
interface testFIINInterface2 {}
|
||||
|
||||
/* testInterface */
|
||||
interface testFIINInterface {}
|
||||
|
||||
/* testImplementedClass */
|
||||
class testFIINImplementedClass implements testFIINInterface {}
|
||||
|
||||
/* testMultiImplementedClass */
|
||||
class testFIINMultiImplementedClass implements testFIINInterface, testFIINInterface2 {}
|
||||
|
||||
/* testNamespacedClass */
|
||||
class testFIINNamespacedClass implements \PHP_CodeSniffer\Tests\Core\File\testFIINInterface {}
|
||||
|
||||
/* testNonImplementedClass */
|
||||
class testFIINNonImplementedClass {}
|
||||
|
||||
/* testClassThatExtendsAndImplements */
|
||||
class testFECNClassThatExtendsAndImplements extends testFECNClass implements InterfaceA, \NameSpaced\Cat\InterfaceB {}
|
||||
|
||||
/* testClassThatImplementsAndExtends */
|
||||
class testFECNClassThatImplementsAndExtends implements \InterfaceA, InterfaceB extends testFECNClass {}
|
||||
|
||||
/* testBackedEnumWithoutImplements */
|
||||
enum Suit:string {}
|
||||
|
||||
/* testEnumImplements */
|
||||
enum Suit implements Colorful {}
|
||||
|
||||
/* testBackedEnumImplements */
|
||||
enum Suit: string implements Colorful, \Deck {}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File:findImplementedInterfaceNames method.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class FindImplementedInterfaceNamesTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test retrieving the name(s) of the interfaces being implemented by a class.
|
||||
*
|
||||
* @param string $identifier Comment which precedes the test case.
|
||||
* @param bool $expected Expected function output.
|
||||
*
|
||||
* @dataProvider dataImplementedInterface
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFindImplementedInterfaceNames($identifier, $expected)
|
||||
{
|
||||
$OOToken = $this->getTargetToken($identifier, [T_CLASS, T_ANON_CLASS, T_INTERFACE, T_ENUM]);
|
||||
$result = self::$phpcsFile->findImplementedInterfaceNames($OOToken);
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
}//end testFindImplementedInterfaceNames()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider for the FindImplementedInterfaceNames test.
|
||||
*
|
||||
* @see testFindImplementedInterfaceNames()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataImplementedInterface()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testImplementedClass */',
|
||||
['testFIINInterface'],
|
||||
],
|
||||
[
|
||||
'/* testMultiImplementedClass */',
|
||||
[
|
||||
'testFIINInterface',
|
||||
'testFIINInterface2',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNamespacedClass */',
|
||||
['\PHP_CodeSniffer\Tests\Core\File\testFIINInterface'],
|
||||
],
|
||||
[
|
||||
'/* testNonImplementedClass */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testInterface */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testClassThatExtendsAndImplements */',
|
||||
[
|
||||
'InterfaceA',
|
||||
'\NameSpaced\Cat\InterfaceB',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testClassThatImplementsAndExtends */',
|
||||
[
|
||||
'\InterfaceA',
|
||||
'InterfaceB',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testBackedEnumWithoutImplements */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testEnumImplements */',
|
||||
['Colorful'],
|
||||
],
|
||||
[
|
||||
'/* testBackedEnumImplements */',
|
||||
[
|
||||
'Colorful',
|
||||
'\Deck',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataImplementedInterface()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+123
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
/* testSimpleAssignment */
|
||||
$a = false;
|
||||
|
||||
/* testFunctionCall */
|
||||
$a = doSomething();
|
||||
|
||||
/* testFunctionCallArgument */
|
||||
$a = doSomething($a, $b);
|
||||
|
||||
/* testControlStructure */
|
||||
while(true) {}
|
||||
$a = 1;
|
||||
|
||||
/* testClosureAssignment */
|
||||
$a = function($b=false;){};
|
||||
|
||||
/* testHeredocFunctionArg */
|
||||
myFunction(<<<END
|
||||
Foo
|
||||
END
|
||||
, 'bar');
|
||||
|
||||
switch ($a) {
|
||||
case 1: {break;}
|
||||
case 2: $foo = true; break;
|
||||
default: {break;}
|
||||
/* testSwitch */
|
||||
}
|
||||
|
||||
/* testStatementAsArrayValue */
|
||||
$a = [new Datetime];
|
||||
$a = array(new Datetime);
|
||||
$a = ['a' => $foo + $bar, 'b' => true];
|
||||
|
||||
/* testUseGroup */
|
||||
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
|
||||
|
||||
$a = [
|
||||
/* testArrowFunctionArrayValue */
|
||||
'a' => fn() => return 1,
|
||||
'b' => fn() => return 1,
|
||||
];
|
||||
|
||||
/* testStaticArrowFunction */
|
||||
static fn ($a) => $a;
|
||||
|
||||
/* testArrowFunctionReturnValue */
|
||||
fn(): array => [a($a, $b)];
|
||||
|
||||
/* testArrowFunctionAsArgument */
|
||||
$foo = foo(
|
||||
fn() => bar()
|
||||
);
|
||||
|
||||
/* testArrowFunctionWithArrayAsArgument */
|
||||
$foo = foo(
|
||||
fn() => [$row[0], $row[3]]
|
||||
);
|
||||
|
||||
$match = match ($a) {
|
||||
/* testMatchCase */
|
||||
1 => 'foo',
|
||||
/* testMatchDefault */
|
||||
default => 'bar'
|
||||
};
|
||||
|
||||
$match = match ($a) {
|
||||
/* testMatchMultipleCase */
|
||||
1, 2, => $a * $b,
|
||||
/* testMatchDefaultComma */
|
||||
default, => 'something'
|
||||
};
|
||||
|
||||
match ($pressedKey) {
|
||||
/* testMatchFunctionCall */
|
||||
Key::RETURN_ => save($value, $user)
|
||||
};
|
||||
|
||||
$result = match (true) {
|
||||
/* testMatchFunctionCallArm */
|
||||
str_contains($text, 'Welcome') || str_contains($text, 'Hello') => 'en',
|
||||
str_contains($text, 'Bienvenue') || str_contains($text, 'Bonjour') => 'fr',
|
||||
default => 'pl'
|
||||
};
|
||||
|
||||
/* testMatchClosure */
|
||||
$result = match ($key) {
|
||||
1 => function($a, $b) {},
|
||||
2 => function($b, $c) {},
|
||||
};
|
||||
|
||||
/* testMatchArray */
|
||||
$result = match ($key) {
|
||||
1 => [1,2,3],
|
||||
2 => [1 => one($a, $b), 2 => two($b, $c)],
|
||||
3 => [],
|
||||
};
|
||||
|
||||
/* testNestedMatch */
|
||||
$result = match ($key) {
|
||||
1 => match ($key) {
|
||||
1 => 'one',
|
||||
2 => 'two',
|
||||
},
|
||||
2 => match ($key) {
|
||||
1 => 'two',
|
||||
2 => 'one',
|
||||
},
|
||||
};
|
||||
|
||||
return 0;
|
||||
|
||||
/* testOpenTag */
|
||||
?>
|
||||
<h1>Test</h1>
|
||||
<?php echo '<h2>', foo(), '</h2>';
|
||||
|
||||
/* testOpenTagWithEcho */
|
||||
?>
|
||||
<h1>Test</h1>
|
||||
<?= '<h2>', foo(), '</h2>';
|
||||
Vendored
+503
@@ -0,0 +1,503 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File:findStartOfStatement method.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class FindStartOfStatementTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test a simple assignment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSimpleAssignment()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testSimpleAssignment */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 5), $found);
|
||||
|
||||
}//end testSimpleAssignment()
|
||||
|
||||
|
||||
/**
|
||||
* Test a function call.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFunctionCall()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testFunctionCall */', T_CLOSE_PARENTHESIS);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
}//end testFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test a function call.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFunctionCallArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testFunctionCallArgument */', T_VARIABLE, '$b');
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testFunctionCallArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test a direct call to a control structure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testControlStructure()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testControlStructure */', T_CLOSE_CURLY_BRACKET);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
}//end testControlStructure()
|
||||
|
||||
|
||||
/**
|
||||
* Test the assignment of a closure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testClosureAssignment()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testClosureAssignment */', T_CLOSE_CURLY_BRACKET);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 12), $found);
|
||||
|
||||
}//end testClosureAssignment()
|
||||
|
||||
|
||||
/**
|
||||
* Test using a heredoc in a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredocFunctionArg()
|
||||
{
|
||||
// Find the start of the function.
|
||||
$start = $this->getTargetToken('/* testHeredocFunctionArg */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 10), $found);
|
||||
|
||||
// Find the start of the heredoc.
|
||||
$start -= 4;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 4), $found);
|
||||
|
||||
// Find the start of the last arg.
|
||||
$start += 2;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testHeredocFunctionArg()
|
||||
|
||||
|
||||
/**
|
||||
* Test parts of a switch statement.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSwitch()
|
||||
{
|
||||
// Find the start of the switch.
|
||||
$start = $this->getTargetToken('/* testSwitch */', T_CLOSE_CURLY_BRACKET);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 47), $found);
|
||||
|
||||
// Find the start of default case.
|
||||
$start -= 5;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
// Find the start of the second case.
|
||||
$start -= 12;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 5), $found);
|
||||
|
||||
// Find the start of the first case.
|
||||
$start -= 13;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 8), $found);
|
||||
|
||||
// Test inside the first case.
|
||||
$start--;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
}//end testSwitch()
|
||||
|
||||
|
||||
/**
|
||||
* Test statements that are array values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStatementAsArrayValue()
|
||||
{
|
||||
// Test short array syntax.
|
||||
$start = $this->getTargetToken('/* testStatementAsArrayValue */', T_STRING, 'Datetime');
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 2), $found);
|
||||
|
||||
// Test long array syntax.
|
||||
$start += 12;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 2), $found);
|
||||
|
||||
// Test same statement outside of array.
|
||||
$start++;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 9), $found);
|
||||
|
||||
// Test with an array index.
|
||||
$start += 17;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 5), $found);
|
||||
|
||||
}//end testStatementAsArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test a use group.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUseGroup()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testUseGroup */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 23), $found);
|
||||
|
||||
}//end testUseGroup()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function as array value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionArrayValue()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_COMMA);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 9), $found);
|
||||
|
||||
}//end testArrowFunctionArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test static arrow function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStaticArrowFunction()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testStaticArrowFunction */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 11), $found);
|
||||
|
||||
}//end testStaticArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with return value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionReturnValue()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionReturnValue */', T_SEMICOLON);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 18), $found);
|
||||
|
||||
}//end testArrowFunctionReturnValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function used as a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionAsArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionAsArgument */', T_FN);
|
||||
$start += 8;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 8), $found);
|
||||
|
||||
}//end testArrowFunctionAsArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with arrays used as a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionWithArrayAsArgument()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testArrowFunctionWithArrayAsArgument */', T_FN);
|
||||
$start += 17;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 17), $found);
|
||||
|
||||
}//end testArrowFunctionWithArrayAsArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test simple match expression case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchCase()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchCase */', T_COMMA);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
}//end testMatchCase()
|
||||
|
||||
|
||||
/**
|
||||
* Test simple match expression default case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchDefault()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchDefault */', T_CONSTANT_ENCAPSED_STRING, "'bar'");
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testMatchDefault()
|
||||
|
||||
|
||||
/**
|
||||
* Test multiple comma-separated match expression case values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchMultipleCase()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchMultipleCase */', T_MATCH_ARROW);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
$start += 6;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 4), $found);
|
||||
|
||||
}//end testMatchMultipleCase()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression default case with trailing comma.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchDefaultComma()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchDefaultComma */', T_MATCH_ARROW);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 3), $found);
|
||||
|
||||
$start += 2;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
}//end testMatchDefaultComma()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with function call.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchFunctionCall()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchFunctionCall */', T_CLOSE_PARENTHESIS);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 6), $found);
|
||||
|
||||
}//end testMatchFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with function call in the arm.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchFunctionCallArm()
|
||||
{
|
||||
// Check the first case.
|
||||
$start = $this->getTargetToken('/* testMatchFunctionCallArm */', T_MATCH_ARROW);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 18), $found);
|
||||
|
||||
// Check the second case.
|
||||
$start += 24;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 18), $found);
|
||||
|
||||
}//end testMatchFunctionCallArm()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with closure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchClosure()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testMatchClosure */', T_LNUMBER);
|
||||
$start += 14;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 10), $found);
|
||||
|
||||
$start += 17;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 10), $found);
|
||||
|
||||
}//end testMatchClosure()
|
||||
|
||||
|
||||
/**
|
||||
* Test match expression with array declaration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchArray()
|
||||
{
|
||||
// Start of first case statement.
|
||||
$start = $this->getTargetToken('/* testMatchArray */', T_LNUMBER);
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
// Comma after first statement.
|
||||
$start += 11;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
$this->assertSame(($start - 7), $found);
|
||||
|
||||
// Start of second case statement.
|
||||
$start += 3;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
$this->assertSame($start, $found);
|
||||
|
||||
// Comma after first statement.
|
||||
$start += 30;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
$this->assertSame(($start - 26), $found);
|
||||
|
||||
}//end testMatchArray()
|
||||
|
||||
|
||||
/**
|
||||
* Test nested match expressions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedMatch()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testNestedMatch */', T_LNUMBER);
|
||||
$start += 30;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 26), $found);
|
||||
|
||||
$start -= 4;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
$start -= 3;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 2), $found);
|
||||
|
||||
}//end testNestedMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Test PHP open tag.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testOpenTag()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testOpenTag */', T_OPEN_TAG);
|
||||
$start += 2;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
}//end testOpenTag()
|
||||
|
||||
|
||||
/**
|
||||
* Test PHP short open echo tag.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testOpenTagWithEcho()
|
||||
{
|
||||
$start = $this->getTargetToken('/* testOpenTagWithEcho */', T_OPEN_TAG_WITH_ECHO);
|
||||
$start += 3;
|
||||
$found = self::$phpcsFile->findStartOfStatement($start);
|
||||
|
||||
$this->assertSame(($start - 1), $found);
|
||||
|
||||
}//end testOpenTagWithEcho()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+304
@@ -0,0 +1,304 @@
|
||||
<?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 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.
|
||||
public callable|static|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 */
|
||||
// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
|
||||
public null $pseudoTypeNull;
|
||||
|
||||
/* testPHP8PseudoTypeFalse */
|
||||
// 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 $array;
|
||||
|
||||
/* testPHP81ReadonlyWithUnionType */
|
||||
public readonly string|int $readonlyWithUnionType;
|
||||
|
||||
/* testPHP81ReadonlyWithUnionTypeWithNull */
|
||||
protected ReadOnly string|null $readonlyWithUnionTypeWithNull;
|
||||
|
||||
/* testPHP81OnlyReadonlyWithUnionType */
|
||||
readonly string|int $onlyReadonly;
|
||||
};
|
||||
|
||||
$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;
|
||||
|
||||
/* testPHP81NulltableIntersectionType */
|
||||
// Intentional fatal error - nullability is not allowed with intersection type, but that's not the concern of the method.
|
||||
public ?Foo&Bar $nullableIntersectionType;
|
||||
};
|
||||
Vendored
+864
@@ -0,0 +1,864 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File::getMemberProperties method.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class GetMemberPropertiesTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test the getMemberProperties() method.
|
||||
*
|
||||
* @param string $identifier Comment which precedes the test case.
|
||||
* @param bool $expected Expected function output.
|
||||
*
|
||||
* @dataProvider dataGetMemberProperties
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetMemberProperties($identifier, $expected)
|
||||
{
|
||||
$variable = $this->getTargetToken($identifier, T_VARIABLE);
|
||||
$result = self::$phpcsFile->getMemberProperties($variable);
|
||||
|
||||
$this->assertArraySubset($expected, $result, true);
|
||||
|
||||
}//end testGetMemberProperties()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider for the GetMemberProperties test.
|
||||
*
|
||||
* @see testGetMemberProperties()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataGetMemberProperties()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testVar */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testVarType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '?int',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPublic */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPublicType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'string',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testProtected */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testProtectedType */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'bool',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPrivate */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPrivateType */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'array',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testStatic */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testStaticType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '?string',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testStaticVar */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testVarStatic */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPublicStatic */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testProtectedStatic */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPrivateStatic */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNoPrefix */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPublicStaticWithDocblock */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testProtectedStaticWithDocblock */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPrivateStaticWithDocblock */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupType 1 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'float',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupType 2 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'float',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupNullableType 1 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '?string',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupNullableType 2 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '?string',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupProtectedStatic 1 */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupProtectedStatic 2 */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupProtectedStatic 3 */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 1 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 2 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 3 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 4 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 5 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 6 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 7 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMessyNullableType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '?array',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNamespaceType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '\MyNamespace\MyClass',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNullableNamespaceType 1 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '?ClassName',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNullableNamespaceType 2 */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '?Folder\ClassName',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultilineNamespaceType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '\MyNamespace\MyClass\Foo',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPropertyAfterMethod */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInterfaceProperty */',
|
||||
[],
|
||||
],
|
||||
[
|
||||
'/* testNestedProperty 1 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNestedProperty 2 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8MixedTypeHint */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'is_readonly' => false,
|
||||
'type' => 'miXed',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8MixedTypeHintNullable */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '?mixed',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNamespaceOperatorTypeHint */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '?namespace\Name',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8UnionTypesSimple */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'int|float',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8UnionTypesTwoClasses */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'MyClassA|\Package\MyClassB',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8UnionTypesAllBaseTypes */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'array|bool|int|float|NULL|object|string',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8UnionTypesAllPseudoTypes */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'false|mixed|self|parent|iterable|Resource',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8UnionTypesIllegalTypes */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
// Missing static, but that's OK as not an allowed syntax.
|
||||
'type' => 'callable||void',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8UnionTypesNullable */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '?int|float',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8PseudoTypeNull */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'null',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8PseudoTypeFalse */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'false',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8PseudoTypeFalseAndBool */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'bool|FALSE',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8ObjectAndClass */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'object|ClassName',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8PseudoTypeIterableAndArray */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'iterable|array|Traversable',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'int|string|INT',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP81Readonly */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => true,
|
||||
'type' => 'int',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP81ReadonlyWithNullableType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => true,
|
||||
'type' => '?array',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP81ReadonlyWithUnionType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => true,
|
||||
'type' => 'string|int',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP81ReadonlyWithUnionTypeWithNull */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => true,
|
||||
'type' => 'string|null',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP81OnlyReadonlyWithUnionType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => false,
|
||||
'is_readonly' => true,
|
||||
'type' => 'string|int',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8PropertySingleAttribute */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'string',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8PropertyMultipleAttributes */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => '?int|float',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8PropertyMultilineAttribute */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'is_readonly' => false,
|
||||
'type' => 'mixed',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testEnumProperty */',
|
||||
[],
|
||||
],
|
||||
[
|
||||
'/* testPHP81IntersectionTypes */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => 'Foo&Bar',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP81MoreIntersectionTypes */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => 'Foo&Bar&Baz',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP81IllegalIntersectionTypes */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => 'int&string',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP81NulltableIntersectionType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '?Foo&Bar',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataGetMemberProperties()
|
||||
|
||||
|
||||
/**
|
||||
* Test receiving an expected exception when a non property is passed.
|
||||
*
|
||||
* @param string $identifier Comment which precedes the test case.
|
||||
*
|
||||
* @expectedException PHP_CodeSniffer\Exceptions\RuntimeException
|
||||
* @expectedExceptionMessage $stackPtr is not a class member var
|
||||
*
|
||||
* @dataProvider dataNotClassProperty
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotClassPropertyException($identifier)
|
||||
{
|
||||
$variable = $this->getTargetToken($identifier, T_VARIABLE);
|
||||
$result = self::$phpcsFile->getMemberProperties($variable);
|
||||
|
||||
}//end testNotClassPropertyException()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider for the NotClassPropertyException test.
|
||||
*
|
||||
* @see testNotClassPropertyException()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNotClassProperty()
|
||||
{
|
||||
return [
|
||||
['/* testMethodParam */'],
|
||||
['/* testImportedGlobal */'],
|
||||
['/* testLocalVariable */'],
|
||||
['/* testGlobalVariable */'],
|
||||
['/* testNestedMethodParam 1 */'],
|
||||
['/* testNestedMethodParam 2 */'],
|
||||
['/* testEnumMethodParamNotProperty */'],
|
||||
];
|
||||
|
||||
}//end dataNotClassProperty()
|
||||
|
||||
|
||||
/**
|
||||
* Test receiving an expected exception when a non variable is passed.
|
||||
*
|
||||
* @expectedException PHP_CodeSniffer\Exceptions\RuntimeException
|
||||
* @expectedExceptionMessage $stackPtr must be of type T_VARIABLE
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotAVariableException()
|
||||
{
|
||||
$next = $this->getTargetToken('/* testNotAVariable */', T_RETURN);
|
||||
$result = self::$phpcsFile->getMemberProperties($next);
|
||||
|
||||
}//end testNotAVariableException()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+164
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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 */
|
||||
// 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 */
|
||||
// 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) {}
|
||||
}
|
||||
|
||||
/* 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) {};
|
||||
Vendored
+1145
File diff suppressed because it is too large
Load Diff
Vendored
+152
@@ -0,0 +1,152 @@
|
||||
<?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 */ ? //comment
|
||||
array {}
|
||||
|
||||
/* testReturnNamespace */
|
||||
function myFunction(): \MyNamespace\MyClass {}
|
||||
|
||||
/* testReturnMultilineNamespace */
|
||||
function myFunction(): \MyNamespace /** comment *\/ comment */
|
||||
\MyClass /* comment */
|
||||
\Foo {}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
|
||||
function pseudoTypeNull(): null {}
|
||||
|
||||
/* testPHP8PseudoTypeFalse */
|
||||
// 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 {};
|
||||
Vendored
+910
@@ -0,0 +1,910 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File:getMethodProperties method.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class GetMethodPropertiesTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test a basic function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBasicFunction()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testBasicFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Test a function with a return type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReturnFunction()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'array',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testReturnFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Test a closure used as a function argument.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedClosure()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'int',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testNestedClosure()
|
||||
|
||||
|
||||
/**
|
||||
* Test a basic method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBasicMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testBasicMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test a private static method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPrivateStaticMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'return_type' => '',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => true,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPrivateStaticMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test a basic final method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFinalMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'return_type' => '',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => true,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testFinalMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test a protected method with a return type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testProtectedReturnMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'return_type' => 'int',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testProtectedReturnMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test a public method with a return type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPublicReturnMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'return_type' => 'array',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPublicReturnMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test a public method with a nullable return type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNullableReturnMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'return_type' => '?array',
|
||||
'nullable_return_type' => true,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testNullableReturnMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test a public method with a nullable return type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMessyNullableReturnMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'return_type' => '?array',
|
||||
'nullable_return_type' => true,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testMessyNullableReturnMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test a method with a namespaced return type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReturnNamespace()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '\MyNamespace\MyClass',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testReturnNamespace()
|
||||
|
||||
|
||||
/**
|
||||
* Test a method with a messy namespaces return type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReturnMultilineNamespace()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '\MyNamespace\MyClass\Foo',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testReturnMultilineNamespace()
|
||||
|
||||
|
||||
/**
|
||||
* Test a basic abstract method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAbstractMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => true,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => false,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testAbstractMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test an abstract method with a return type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAbstractReturnMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'return_type' => 'bool',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => true,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => false,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testAbstractReturnMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test a basic interface method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInterfaceMethod()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => false,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testInterfaceMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Test a static arrow function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunction()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'int',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => true,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Test a function with return type "static".
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReturnTypeStatic()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'return_type' => 'static',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testReturnTypeStatic()
|
||||
|
||||
|
||||
/**
|
||||
* Test a function with return type "mixed".
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8MixedTypeHint()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'mixed',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8MixedTypeHint()
|
||||
|
||||
|
||||
/**
|
||||
* Test a function with return type "mixed" and nullability.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8MixedTypeHintNullable()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '?mixed',
|
||||
'nullable_return_type' => true,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8MixedTypeHintNullable()
|
||||
|
||||
|
||||
/**
|
||||
* Test a function with return type using the namespace operator.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNamespaceOperatorTypeHint()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '?namespace\Name',
|
||||
'nullable_return_type' => true,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testNamespaceOperatorTypeHint()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 union type declaration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8UnionTypesSimple()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'int|float',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8UnionTypesSimple()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 union type declaration with two classes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8UnionTypesTwoClasses()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'MyClassA|\Package\MyClassB',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8UnionTypesTwoClasses()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 union type declaration with all base types.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8UnionTypesAllBaseTypes()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'array|bool|callable|int|float|null|Object|string',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8UnionTypesAllBaseTypes()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 union type declaration with all pseudo types.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8UnionTypesAllPseudoTypes()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'false|MIXED|self|parent|static|iterable|Resource|void',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8UnionTypesAllPseudoTypes()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 union type declaration with (illegal) nullability.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8UnionTypesNullable()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '?int|float',
|
||||
'nullable_return_type' => true,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8UnionTypesNullable()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 type declaration with (illegal) single type null.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8PseudoTypeNull()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'null',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8PseudoTypeNull()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 type declaration with (illegal) single type false.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8PseudoTypeFalse()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'false',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8PseudoTypeFalse()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8PseudoTypeFalseAndBool()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'bool|false',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8PseudoTypeFalseAndBool()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8ObjectAndClass()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'object|ClassName',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8ObjectAndClass()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8PseudoTypeIterableAndArray()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'return_type' => 'iterable|array|Traversable',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => false,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8PseudoTypeIterableAndArray()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 type declaration with (illegal) duplicate types.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8DuplicateTypeInUnionWhitespaceAndComment()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'int|string|INT',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8DuplicateTypeInUnionWhitespaceAndComment()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8.1 type "never".
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP81NeverType()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'never',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP81NeverType()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8.1 type "never" with (illegal) nullability.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP81NullableNeverType()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '?never',
|
||||
'nullable_return_type' => true,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP81NullableNeverType()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8.1 intersection type declaration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8IntersectionTypes()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'Foo&Bar',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8IntersectionTypes()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8.1 intersection type declaration with more types.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP81MoreIntersectionTypes()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'MyClassA&\Package\MyClassB&\Package\MyClassC',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP81MoreIntersectionTypes()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8.1 intersection type declaration in arrow function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP81IntersectionArrowFunction()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'MyClassA&\Package\MyClassB',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP81IntersectionArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8.1 intersection type declaration with illegal simple types.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP81IllegalIntersectionTypes()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => 'string&int',
|
||||
'nullable_return_type' => false,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP81IllegalIntersectionTypes()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP81NullableIntersectionTypes()
|
||||
{
|
||||
$expected = [
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'return_type' => '?Foo&Bar',
|
||||
'nullable_return_type' => true,
|
||||
'is_abstract' => false,
|
||||
'is_final' => false,
|
||||
'is_static' => false,
|
||||
'has_body' => true,
|
||||
];
|
||||
|
||||
$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP81NullableIntersectionTypes()
|
||||
|
||||
|
||||
/**
|
||||
* Test helper.
|
||||
*
|
||||
* @param string $commentString The comment which preceeds the test.
|
||||
* @param array $expected The expected function output.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function getMethodPropertiesTestHelper($commentString, $expected)
|
||||
{
|
||||
$function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE, T_FN]);
|
||||
$found = self::$phpcsFile->getMethodProperties($function);
|
||||
|
||||
$this->assertArraySubset($expected, $found, true);
|
||||
|
||||
}//end getMethodPropertiesTestHelper()
|
||||
|
||||
|
||||
}//end class
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
/* 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();
|
||||
|
||||
/* 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);
|
||||
|
||||
/* testNewByReferenceA */
|
||||
$foobar2 = &new Foobar();
|
||||
|
||||
/* testNewByReferenceB */
|
||||
functionCall( $something , &new Foobar() );
|
||||
|
||||
/* testUseByReference */
|
||||
$closure = function() use (&$var){};
|
||||
|
||||
/* testArrowFunctionReturnByReference */
|
||||
fn&($x) => $x;
|
||||
|
||||
/* testArrowFunctionPassByReferenceA */
|
||||
$fn = fn(array &$one) => 1;
|
||||
|
||||
/* testArrowFunctionPassByReferenceB */
|
||||
$fn = fn($param, &...$moreParams) => 1;
|
||||
|
||||
/* testClosureReturnByReference */
|
||||
$closure = function &($param) use ($value) {};
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
<?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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\File;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class IsReferenceTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test correctly identifying whether a "bitwise and" token is a reference or not.
|
||||
*
|
||||
* @param string $identifier Comment which precedes the test case.
|
||||
* @param bool $expected Expected function output.
|
||||
*
|
||||
* @dataProvider dataIsReference
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testIsReference($identifier, $expected)
|
||||
{
|
||||
$bitwiseAnd = $this->getTargetToken($identifier, T_BITWISE_AND);
|
||||
$result = self::$phpcsFile->isReference($bitwiseAnd);
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
}//end testIsReference()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider for the IsReference test.
|
||||
*
|
||||
* @see testIsReference()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataIsReference()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testBitwiseAndA */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testBitwiseAndB */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testBitwiseAndC */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testBitwiseAndD */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testBitwiseAndE */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testBitwiseAndF */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testBitwiseAndG */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testBitwiseAndH */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testBitwiseAndI */',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'/* testFunctionReturnByReference */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testFunctionPassByReferenceA */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testFunctionPassByReferenceB */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testFunctionPassByReferenceC */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testFunctionPassByReferenceD */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testFunctionPassByReferenceE */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testFunctionPassByReferenceF */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testFunctionPassByReferenceG */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testForeachValueByReference */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testForeachKeyByReference */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrayValueByReferenceA */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrayValueByReferenceB */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrayValueByReferenceC */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrayValueByReferenceD */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrayValueByReferenceE */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrayValueByReferenceF */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrayValueByReferenceG */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrayValueByReferenceH */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testAssignByReferenceA */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testAssignByReferenceB */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testAssignByReferenceC */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testAssignByReferenceD */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testAssignByReferenceE */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceA */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceB */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceC */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceD */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceE */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceF */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceG */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceH */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceI */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testPassByReferenceJ */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testNewByReferenceA */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testNewByReferenceB */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testUseByReference */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrowFunctionReturnByReference */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrowFunctionPassByReferenceA */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testArrowFunctionPassByReferenceB */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testClosureReturnByReference */',
|
||||
true,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataIsReference()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+154
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Filters\Filter::accept method.
|
||||
*
|
||||
* @author Willington Vega <wvega@wvega.com>
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Filters\Filter;
|
||||
|
||||
use PHP_CodeSniffer\Config;
|
||||
use PHP_CodeSniffer\Filters\Filter;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AcceptTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* The Config object.
|
||||
*
|
||||
* @var \PHP_CodeSniffer\Config
|
||||
*/
|
||||
protected static $config;
|
||||
|
||||
/**
|
||||
* The Ruleset object.
|
||||
*
|
||||
* @var \PHP_CodeSniffer\Ruleset
|
||||
*/
|
||||
protected static $ruleset;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the test.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) {
|
||||
// PEAR installs test and sniff files into different locations
|
||||
// so these tests will not pass as they directly reference files
|
||||
// by relative location.
|
||||
$this->markTestSkipped('Test cannot run from a PEAR install');
|
||||
}
|
||||
|
||||
}//end setUp()
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the config and ruleset objects based on the `AcceptTest.xml` ruleset file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) {
|
||||
// This test will be skipped.
|
||||
return;
|
||||
}
|
||||
|
||||
$standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml';
|
||||
self::$config = new Config(["--standard=$standard", "--ignore=*/somethingelse/*"]);
|
||||
self::$ruleset = new Ruleset(self::$config);
|
||||
|
||||
}//end setUpBeforeClass()
|
||||
|
||||
|
||||
/**
|
||||
* Test filtering a file list for excluded paths.
|
||||
*
|
||||
* @param array $inputPaths List of file paths to be filtered.
|
||||
* @param array $expectedOutput Expected filtering result.
|
||||
*
|
||||
* @dataProvider dataExcludePatterns
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testExcludePatterns($inputPaths, $expectedOutput)
|
||||
{
|
||||
$fakeDI = new \RecursiveArrayIterator($inputPaths);
|
||||
$filter = new Filter($fakeDI, '/', self::$config, self::$ruleset);
|
||||
$iterator = new \RecursiveIteratorIterator($filter);
|
||||
$files = [];
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
$files[] = $file;
|
||||
}
|
||||
|
||||
$this->assertEquals($expectedOutput, $files);
|
||||
|
||||
}//end testExcludePatterns()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testExcludePatterns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataExcludePatterns()
|
||||
{
|
||||
$testCases = [
|
||||
// Test top-level exclude patterns.
|
||||
[
|
||||
[
|
||||
'/path/to/src/Main.php',
|
||||
'/path/to/src/Something/Main.php',
|
||||
'/path/to/src/Somethingelse/Main.php',
|
||||
'/path/to/src/SomethingelseEvenLonger/Main.php',
|
||||
'/path/to/src/Other/Main.php',
|
||||
],
|
||||
[
|
||||
'/path/to/src/Main.php',
|
||||
'/path/to/src/SomethingelseEvenLonger/Main.php',
|
||||
],
|
||||
],
|
||||
|
||||
// Test ignoring standard/sniff specific exclude patterns.
|
||||
[
|
||||
[
|
||||
'/path/to/src/generic-project/Main.php',
|
||||
'/path/to/src/generic/Main.php',
|
||||
'/path/to/src/anything-generic/Main.php',
|
||||
],
|
||||
[
|
||||
'/path/to/src/generic-project/Main.php',
|
||||
'/path/to/src/generic/Main.php',
|
||||
'/path/to/src/anything-generic/Main.php',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Allow these tests to work on Windows as well.
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
foreach ($testCases as $key => $case) {
|
||||
foreach ($case as $nr => $param) {
|
||||
foreach ($param as $file => $value) {
|
||||
$testCases[$key][$nr][$file] = strtr($value, '/', '\\');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $testCases;
|
||||
|
||||
}//end dataExcludePatterns()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="AcceptTest" xsi:noNamespaceSchemaLocation="phpcs.xsd">
|
||||
<description>Ruleset to test the filtering based on exclude patterns.</description>
|
||||
|
||||
<!-- Directory pattern. -->
|
||||
<exclude-pattern>*/something/*</exclude-pattern>
|
||||
<!-- File pattern. -->
|
||||
<exclude-pattern>*/Other/Main\.php$</exclude-pattern>
|
||||
|
||||
<rule ref="Generic">
|
||||
<!-- Standard specific directory pattern. -->
|
||||
<exclude-pattern>/anything/*</exclude-pattern>
|
||||
<!-- Standard specific file pattern. -->
|
||||
<exclude-pattern>/YetAnother/Main\.php</exclude-pattern>
|
||||
</rule>
|
||||
</ruleset>
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Util\Common::isCamelCaps method.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core;
|
||||
|
||||
use PHP_CodeSniffer\Util\Common;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class IsCamelCapsTest extends TestCase
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test valid public function/method names.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testValidNotClassFormatPublic()
|
||||
{
|
||||
$this->assertTrue(Common::isCamelCaps('thisIsCamelCaps', false, true, true));
|
||||
$this->assertTrue(Common::isCamelCaps('thisISCamelCaps', false, true, false));
|
||||
|
||||
}//end testValidNotClassFormatPublic()
|
||||
|
||||
|
||||
/**
|
||||
* Test invalid public function/method names.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidNotClassFormatPublic()
|
||||
{
|
||||
$this->assertFalse(Common::isCamelCaps('_thisIsCamelCaps', false, true, true));
|
||||
$this->assertFalse(Common::isCamelCaps('thisISCamelCaps', false, true, true));
|
||||
$this->assertFalse(Common::isCamelCaps('ThisIsCamelCaps', false, true, true));
|
||||
|
||||
$this->assertFalse(Common::isCamelCaps('3thisIsCamelCaps', false, true, true));
|
||||
$this->assertFalse(Common::isCamelCaps('*thisIsCamelCaps', false, true, true));
|
||||
$this->assertFalse(Common::isCamelCaps('-thisIsCamelCaps', false, true, true));
|
||||
|
||||
$this->assertFalse(Common::isCamelCaps('this*IsCamelCaps', false, true, true));
|
||||
$this->assertFalse(Common::isCamelCaps('this-IsCamelCaps', false, true, true));
|
||||
$this->assertFalse(Common::isCamelCaps('this_IsCamelCaps', false, true, true));
|
||||
$this->assertFalse(Common::isCamelCaps('this_is_camel_caps', false, true, true));
|
||||
|
||||
}//end testInvalidNotClassFormatPublic()
|
||||
|
||||
|
||||
/**
|
||||
* Test valid private method names.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testValidNotClassFormatPrivate()
|
||||
{
|
||||
$this->assertTrue(Common::isCamelCaps('_thisIsCamelCaps', false, false, true));
|
||||
$this->assertTrue(Common::isCamelCaps('_thisISCamelCaps', false, false, false));
|
||||
$this->assertTrue(Common::isCamelCaps('_i18N', false, false, true));
|
||||
$this->assertTrue(Common::isCamelCaps('_i18n', false, false, true));
|
||||
|
||||
}//end testValidNotClassFormatPrivate()
|
||||
|
||||
|
||||
/**
|
||||
* Test invalid private method names.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidNotClassFormatPrivate()
|
||||
{
|
||||
$this->assertFalse(Common::isCamelCaps('thisIsCamelCaps', false, false, true));
|
||||
$this->assertFalse(Common::isCamelCaps('_thisISCamelCaps', false, false, true));
|
||||
$this->assertFalse(Common::isCamelCaps('_ThisIsCamelCaps', false, false, true));
|
||||
$this->assertFalse(Common::isCamelCaps('__thisIsCamelCaps', false, false, true));
|
||||
$this->assertFalse(Common::isCamelCaps('__thisISCamelCaps', false, false, false));
|
||||
|
||||
$this->assertFalse(Common::isCamelCaps('3thisIsCamelCaps', false, false, true));
|
||||
$this->assertFalse(Common::isCamelCaps('*thisIsCamelCaps', false, false, true));
|
||||
$this->assertFalse(Common::isCamelCaps('-thisIsCamelCaps', false, false, true));
|
||||
$this->assertFalse(Common::isCamelCaps('_this_is_camel_caps', false, false, true));
|
||||
|
||||
}//end testInvalidNotClassFormatPrivate()
|
||||
|
||||
|
||||
/**
|
||||
* Test valid class names.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testValidClassFormatPublic()
|
||||
{
|
||||
$this->assertTrue(Common::isCamelCaps('ThisIsCamelCaps', true, true, true));
|
||||
$this->assertTrue(Common::isCamelCaps('ThisISCamelCaps', true, true, false));
|
||||
$this->assertTrue(Common::isCamelCaps('This3IsCamelCaps', true, true, false));
|
||||
|
||||
}//end testValidClassFormatPublic()
|
||||
|
||||
|
||||
/**
|
||||
* Test invalid class names.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidClassFormat()
|
||||
{
|
||||
$this->assertFalse(Common::isCamelCaps('thisIsCamelCaps', true));
|
||||
$this->assertFalse(Common::isCamelCaps('This-IsCamelCaps', true));
|
||||
$this->assertFalse(Common::isCamelCaps('This_Is_Camel_Caps', true));
|
||||
|
||||
}//end testInvalidClassFormat()
|
||||
|
||||
|
||||
/**
|
||||
* Test invalid class names with the private flag set.
|
||||
*
|
||||
* Note that the private flag is ignored if the class format
|
||||
* flag is set, so these names are all invalid.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidClassFormatPrivate()
|
||||
{
|
||||
$this->assertFalse(Common::isCamelCaps('_ThisIsCamelCaps', true, true));
|
||||
$this->assertFalse(Common::isCamelCaps('_ThisIsCamelCaps', true, false));
|
||||
|
||||
}//end testInvalidClassFormatPrivate()
|
||||
|
||||
|
||||
}//end class
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Ruleset class using a Linux-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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Ruleset;
|
||||
|
||||
use PHP_CodeSniffer\Config;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RuleInclusionAbsoluteLinuxTest 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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) {
|
||||
// PEAR installs test and sniff files into different locations
|
||||
// so these tests will not pass as they directly reference files
|
||||
// by relative location.
|
||||
$this->markTestSkipped('Test cannot run from a PEAR install');
|
||||
}
|
||||
|
||||
$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;
|
||||
|
||||
$newPath = $repoRootDir;
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
$newPath = str_replace('\\', '/', $repoRootDir);
|
||||
}
|
||||
|
||||
$adjusted = str_replace('%path_slash_forward%', $newPath, $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 Config(["--standard={$this->standard}"]);
|
||||
$this->ruleset = new Ruleset($config);
|
||||
|
||||
}//end setUp()
|
||||
|
||||
|
||||
/**
|
||||
* Reset ruleset file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
file_put_contents($this->standard, $this->contents);
|
||||
|
||||
}//end tearDown()
|
||||
|
||||
|
||||
/**
|
||||
* Test that sniffs registed with a Linux absolute path are correctly recognized and that
|
||||
* properties are correctly set for them.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testLinuxStylePathRuleInclusion()
|
||||
{
|
||||
// Test that the sniff is correctly registered.
|
||||
$this->assertObjectHasAttribute('sniffCodes', $this->ruleset);
|
||||
$this->assertCount(1, $this->ruleset->sniffCodes);
|
||||
$this->assertArrayHasKey('Generic.Formatting.SpaceAfterNot', $this->ruleset->sniffCodes);
|
||||
$this->assertSame(
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Formatting\SpaceAfterNotSniff',
|
||||
$this->ruleset->sniffCodes['Generic.Formatting.SpaceAfterNot']
|
||||
);
|
||||
|
||||
// Test that the sniff properties are correctly set.
|
||||
$this->assertSame(
|
||||
'10',
|
||||
$this->ruleset->sniffs['PHP_CodeSniffer\Standards\Generic\Sniffs\Formatting\SpaceAfterNotSniff']->spacing
|
||||
);
|
||||
|
||||
}//end testLinuxStylePathRuleInclusion()
|
||||
|
||||
|
||||
}//end class
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="RuleInclusionAbsoluteLinuxTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/squizlabs/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<!-- %path_slash_forward% will be replaced on the fly -->
|
||||
<rule ref="%path_slash_forward%/src/Standards/Generic/Sniffs/Formatting/SpaceAfterNotSniff.php">
|
||||
<properties>
|
||||
<property name="spacing" value="10" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
<?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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Ruleset;
|
||||
|
||||
use PHP_CodeSniffer\Config;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
if (DIRECTORY_SEPARATOR === '/') {
|
||||
$this->markTestSkipped('Windows specific test');
|
||||
}
|
||||
|
||||
if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) {
|
||||
// PEAR installs test and sniff files into different locations
|
||||
// so these tests will not pass as they directly reference files
|
||||
// by relative location.
|
||||
$this->markTestSkipped('Test cannot run from a PEAR install');
|
||||
}
|
||||
|
||||
$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 Config(["--standard={$this->standard}"]);
|
||||
$this->ruleset = new Ruleset($config);
|
||||
|
||||
}//end setUp()
|
||||
|
||||
|
||||
/**
|
||||
* Reset ruleset file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
if (DIRECTORY_SEPARATOR !== '/') {
|
||||
file_put_contents($this->standard, $this->contents);
|
||||
}
|
||||
|
||||
}//end tearDown()
|
||||
|
||||
|
||||
/**
|
||||
* 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->assertObjectHasAttribute('sniffCodes', $this->ruleset);
|
||||
$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
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="RuleInclusionAbsoluteWindowsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/squizlabs/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<!-- %path_slash_back% will be replaced on the fly -->
|
||||
<rule ref="%path_slash_back%\src\Standards\Generic\Sniffs\Formatting\SpaceAfterCastSniff.php">
|
||||
<properties>
|
||||
<property name="spacing" value="10" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="RuleInclusionTest-include" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/squizlabs/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="Generic.Metrics.NestingLevel">
|
||||
<properties>
|
||||
<property name="nestingLevel" value="2" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
Vendored
+297
@@ -0,0 +1,297 @@
|
||||
<?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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Ruleset;
|
||||
|
||||
use PHP_CodeSniffer\Config;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RuleInclusionTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* 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 test.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) {
|
||||
// PEAR installs test and sniff files into different locations
|
||||
// so these tests will not pass as they directly reference files
|
||||
// by relative location.
|
||||
$this->markTestSkipped('Test cannot run from a PEAR install');
|
||||
}
|
||||
|
||||
}//end setUp()
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the config and ruleset objects based on the `RuleInclusionTest.xml` ruleset file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) {
|
||||
// This test will be skipped.
|
||||
return;
|
||||
}
|
||||
|
||||
$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 Config(["--standard=$standard"]);
|
||||
self::$ruleset = new Ruleset($config);
|
||||
|
||||
}//end setUpBeforeClass()
|
||||
|
||||
|
||||
/**
|
||||
* Reset ruleset file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
file_put_contents(self::$standard, self::$contents);
|
||||
|
||||
}//end tearDown()
|
||||
|
||||
|
||||
/**
|
||||
* Test that sniffs are registered.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHasSniffCodes()
|
||||
{
|
||||
$this->assertObjectHasAttribute('sniffCodes', self::$ruleset);
|
||||
$this->assertCount(14, self::$ruleset->sniffCodes);
|
||||
|
||||
}//end testHasSniffCodes()
|
||||
|
||||
|
||||
/**
|
||||
* Test that sniffs are correctly registered, independently on 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
|
||||
*/
|
||||
public function dataRegisteredSniffCodes()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'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',
|
||||
],
|
||||
[
|
||||
'Zend.NamingConventions.ValidVariableName',
|
||||
'PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions\ValidVariableNameSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Arrays.ArrayIndent',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff',
|
||||
],
|
||||
[
|
||||
'Generic.Metrics.CyclomaticComplexity',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff',
|
||||
],
|
||||
[
|
||||
'Generic.Files.LineLength',
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff',
|
||||
],
|
||||
[
|
||||
'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 mixed $expectedValue The value expected for the property.
|
||||
*
|
||||
* @dataProvider dataSettingProperties
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSettingProperties($sniffClass, $propertyName, $expectedValue)
|
||||
{
|
||||
$this->assertObjectHasAttribute('sniffs', self::$ruleset);
|
||||
$this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs);
|
||||
$this->assertObjectHasAttribute($propertyName, self::$ruleset->sniffs[$sniffClass]);
|
||||
|
||||
$actualValue = self::$ruleset->sniffs[$sniffClass]->$propertyName;
|
||||
$this->assertSame($expectedValue, $actualValue);
|
||||
|
||||
}//end testSettingProperties()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see self::testSettingProperties()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataSettingProperties()
|
||||
{
|
||||
return [
|
||||
'ClassDeclarationSniff' => [
|
||||
'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff',
|
||||
'setforallsniffs',
|
||||
true,
|
||||
],
|
||||
'SideEffectsSniff' => [
|
||||
'PHP_CodeSniffer\Standards\PSR1\Sniffs\Files\SideEffectsSniff',
|
||||
'setforallsniffs',
|
||||
true,
|
||||
],
|
||||
'ValidVariableNameSniff' => [
|
||||
'PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions\ValidVariableNameSniff',
|
||||
'setforallincategory',
|
||||
true,
|
||||
],
|
||||
'ArrayIndentSniff' => [
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff',
|
||||
'indent',
|
||||
'2',
|
||||
],
|
||||
'LineLengthSniff' => [
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff',
|
||||
'lineLimit',
|
||||
'10',
|
||||
],
|
||||
'CamelCapsFunctionNameSniff' => [
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff',
|
||||
'strict',
|
||||
false,
|
||||
],
|
||||
'NestingLevelSniff-nestingLevel' => [
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff',
|
||||
'nestingLevel',
|
||||
'2',
|
||||
],
|
||||
'NestingLevelSniff-setforsniffsinincludedruleset' => [
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff',
|
||||
'setforsniffsinincludedruleset',
|
||||
true,
|
||||
],
|
||||
|
||||
// Testing that setting a property at error code level does *not* work.
|
||||
'CyclomaticComplexitySniff' => [
|
||||
'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff',
|
||||
'complexity',
|
||||
10,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataSettingProperties()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="RuleInclusionTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/squizlabs/PHP_CodeSniffer/master/phpcs.xsd">
|
||||
|
||||
<rule ref="PSR1">
|
||||
<properties>
|
||||
<property name="setforallsniffs" value="true" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="Zend.NamingConventions">
|
||||
<properties>
|
||||
<property name="setforallincategory" value="true" />
|
||||
</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>
|
||||
|
||||
<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>
|
||||
|
||||
<rule ref="./RuleInclusionTest-include.xml">
|
||||
<properties>
|
||||
<property name="setforsniffsinincludedruleset" value="true" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
Vendored
+51
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/* testSimpleValues */
|
||||
$foo = [1,2,3];
|
||||
|
||||
/* testSimpleKeyValues */
|
||||
$foo = ['1'=>1,'2'=>2,'3'=>3];
|
||||
|
||||
/* testMissingKeys */
|
||||
$foo = ['1'=>1,2,'3'=>3];
|
||||
|
||||
/* testMultiTokenKeys */
|
||||
$paths = array(
|
||||
Init::ROOT_DIR.'/a' => 'a',
|
||||
Init::ROOT_DIR.'/b' => 'b',
|
||||
);
|
||||
|
||||
/* testMissingKeysCoalesceTernary */
|
||||
return [
|
||||
$a => static function () { return [1,2,3]; },
|
||||
$b ?? $c,
|
||||
$d ? [$e] : [$f],
|
||||
];
|
||||
|
||||
/* testTernaryValues */
|
||||
$foo = [
|
||||
'1' => $row['status'] === 'rejected'
|
||||
? self::REJECTED_CODE
|
||||
: self::VERIFIED_CODE,
|
||||
'2' => in_array($row['status'], array('notverified', 'unverified'), true)
|
||||
? self::STATUS_PENDING
|
||||
: self::STATUS_VERIFIED,
|
||||
'3' => strtotime($row['date']),
|
||||
];
|
||||
|
||||
/* testHeredocValues */
|
||||
$foo = array(
|
||||
<<<HERE
|
||||
HERE
|
||||
,
|
||||
<<<HERE
|
||||
HERE
|
||||
,
|
||||
);
|
||||
|
||||
/* testArrowFunctionValue */
|
||||
$foo = array(
|
||||
1 => '1',
|
||||
2 => fn ($x) => yield 'a' => $x,
|
||||
3 => '3',
|
||||
);
|
||||
Vendored
+290
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Sniffs\AbstractArraySniff.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Sniffs;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class AbstractArraySniffTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
/**
|
||||
* The sniff objects we are testing.
|
||||
*
|
||||
* This extends the \PHP_CodeSniffer\Sniffs\AbstractArraySniff class to make the
|
||||
* internal workings of the sniff observable.
|
||||
*
|
||||
* @var \PHP_CodeSniffer\Sniffs\AbstractArraySniffTestable
|
||||
*/
|
||||
protected static $sniff;
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$sniff = new AbstractArraySniffTestable();
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
}//end setUpBeforeClass()
|
||||
|
||||
|
||||
/**
|
||||
* Test an array of simple values only.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSimpleValues()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testSimpleValues */', T_OPEN_SHORT_ARRAY);
|
||||
self::$sniff->process(self::$phpcsFile, $token);
|
||||
|
||||
$expected = [
|
||||
0 => ['value_start' => ($token + 1)],
|
||||
1 => ['value_start' => ($token + 3)],
|
||||
2 => ['value_start' => ($token + 5)],
|
||||
];
|
||||
|
||||
$this->assertSame($expected, self::$sniff->indicies);
|
||||
|
||||
}//end testSimpleValues()
|
||||
|
||||
|
||||
/**
|
||||
* Test an array of simple keys and values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSimpleKeyValues()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testSimpleKeyValues */', T_OPEN_SHORT_ARRAY);
|
||||
self::$sniff->process(self::$phpcsFile, $token);
|
||||
|
||||
$expected = [
|
||||
0 => [
|
||||
'index_start' => ($token + 1),
|
||||
'index_end' => ($token + 1),
|
||||
'arrow' => ($token + 2),
|
||||
'value_start' => ($token + 3),
|
||||
],
|
||||
1 => [
|
||||
'index_start' => ($token + 5),
|
||||
'index_end' => ($token + 5),
|
||||
'arrow' => ($token + 6),
|
||||
'value_start' => ($token + 7),
|
||||
],
|
||||
2 => [
|
||||
'index_start' => ($token + 9),
|
||||
'index_end' => ($token + 9),
|
||||
'arrow' => ($token + 10),
|
||||
'value_start' => ($token + 11),
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertSame($expected, self::$sniff->indicies);
|
||||
|
||||
}//end testSimpleKeyValues()
|
||||
|
||||
|
||||
/**
|
||||
* Test an array of simple keys and values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMissingKeys()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testMissingKeys */', T_OPEN_SHORT_ARRAY);
|
||||
self::$sniff->process(self::$phpcsFile, $token);
|
||||
|
||||
$expected = [
|
||||
0 => [
|
||||
'index_start' => ($token + 1),
|
||||
'index_end' => ($token + 1),
|
||||
'arrow' => ($token + 2),
|
||||
'value_start' => ($token + 3),
|
||||
],
|
||||
1 => [
|
||||
'value_start' => ($token + 5),
|
||||
],
|
||||
2 => [
|
||||
'index_start' => ($token + 7),
|
||||
'index_end' => ($token + 7),
|
||||
'arrow' => ($token + 8),
|
||||
'value_start' => ($token + 9),
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertSame($expected, self::$sniff->indicies);
|
||||
|
||||
}//end testMissingKeys()
|
||||
|
||||
|
||||
/**
|
||||
* Test an array with keys that span multiple tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMultiTokenKeys()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testMultiTokenKeys */', T_ARRAY);
|
||||
self::$sniff->process(self::$phpcsFile, $token);
|
||||
|
||||
$expected = [
|
||||
0 => [
|
||||
'index_start' => ($token + 4),
|
||||
'index_end' => ($token + 8),
|
||||
'arrow' => ($token + 10),
|
||||
'value_start' => ($token + 12),
|
||||
],
|
||||
1 => [
|
||||
'index_start' => ($token + 16),
|
||||
'index_end' => ($token + 20),
|
||||
'arrow' => ($token + 22),
|
||||
'value_start' => ($token + 24),
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertSame($expected, self::$sniff->indicies);
|
||||
|
||||
}//end testMultiTokenKeys()
|
||||
|
||||
|
||||
/**
|
||||
* Test an array of simple keys and values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMissingKeysCoalesceTernary()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testMissingKeysCoalesceTernary */', T_OPEN_SHORT_ARRAY);
|
||||
self::$sniff->process(self::$phpcsFile, $token);
|
||||
|
||||
$expected = [
|
||||
0 => [
|
||||
'index_start' => ($token + 3),
|
||||
'index_end' => ($token + 3),
|
||||
'arrow' => ($token + 5),
|
||||
'value_start' => ($token + 7),
|
||||
],
|
||||
1 => [
|
||||
'value_start' => ($token + 31),
|
||||
],
|
||||
2 => [
|
||||
'value_start' => ($token + 39),
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertSame($expected, self::$sniff->indicies);
|
||||
|
||||
}//end testMissingKeysCoalesceTernary()
|
||||
|
||||
|
||||
/**
|
||||
* Test an array of ternary values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTernaryValues()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testTernaryValues */', T_OPEN_SHORT_ARRAY);
|
||||
self::$sniff->process(self::$phpcsFile, $token);
|
||||
|
||||
$expected = [
|
||||
0 => [
|
||||
'index_start' => ($token + 3),
|
||||
'index_end' => ($token + 3),
|
||||
'arrow' => ($token + 5),
|
||||
'value_start' => ($token + 7),
|
||||
],
|
||||
1 => [
|
||||
'index_start' => ($token + 32),
|
||||
'index_end' => ($token + 32),
|
||||
'arrow' => ($token + 34),
|
||||
'value_start' => ($token + 36),
|
||||
],
|
||||
2 => [
|
||||
'index_start' => ($token + 72),
|
||||
'index_end' => ($token + 72),
|
||||
'arrow' => ($token + 74),
|
||||
'value_start' => ($token + 76),
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertSame($expected, self::$sniff->indicies);
|
||||
|
||||
}//end testTernaryValues()
|
||||
|
||||
|
||||
/**
|
||||
* Test an array of heredocs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredocValues()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testHeredocValues */', T_ARRAY);
|
||||
self::$sniff->process(self::$phpcsFile, $token);
|
||||
|
||||
$expected = [
|
||||
0 => [
|
||||
'value_start' => ($token + 4),
|
||||
],
|
||||
1 => [
|
||||
'value_start' => ($token + 10),
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertSame($expected, self::$sniff->indicies);
|
||||
|
||||
}//end testHeredocValues()
|
||||
|
||||
|
||||
/**
|
||||
* Test an array of with an arrow function as a value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunctionValue()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testArrowFunctionValue */', T_ARRAY);
|
||||
self::$sniff->process(self::$phpcsFile, $token);
|
||||
|
||||
$expected = [
|
||||
0 => [
|
||||
'index_start' => ($token + 4),
|
||||
'index_end' => ($token + 4),
|
||||
'arrow' => ($token + 6),
|
||||
'value_start' => ($token + 8),
|
||||
],
|
||||
1 => [
|
||||
'index_start' => ($token + 12),
|
||||
'index_end' => ($token + 12),
|
||||
'arrow' => ($token + 14),
|
||||
'value_start' => ($token + 16),
|
||||
],
|
||||
2 => [
|
||||
'index_start' => ($token + 34),
|
||||
'index_end' => ($token + 34),
|
||||
'arrow' => ($token + 36),
|
||||
'value_start' => ($token + 38),
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertSame($expected, self::$sniff->indicies);
|
||||
|
||||
}//end testArrowFunctionValue()
|
||||
|
||||
|
||||
}//end class
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* A testable implementation of \PHP_CodeSniffer\Sniffs\AbstractArraySniff.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2006-2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Sniffs;
|
||||
|
||||
use PHP_CodeSniffer\Sniffs\AbstractArraySniff;
|
||||
|
||||
class AbstractArraySniffTestable extends AbstractArraySniff
|
||||
{
|
||||
|
||||
/**
|
||||
* The array indicies that were found during processing.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $indicies = [];
|
||||
|
||||
|
||||
/**
|
||||
* Processes a single-line array definition.
|
||||
*
|
||||
* @param \PHP_CodeSniffer\Files\File $phpcsFile The current file being checked.
|
||||
* @param int $stackPtr The position of the current token
|
||||
* in the stack passed in $tokens.
|
||||
* @param int $arrayStart The token that starts the array definition.
|
||||
* @param int $arrayEnd The token that ends the array definition.
|
||||
* @param array $indices An array of token positions for the array keys,
|
||||
* double arrows, and values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function processSingleLineArray($phpcsFile, $stackPtr, $arrayStart, $arrayEnd, $indices)
|
||||
{
|
||||
$this->indicies = $indices;
|
||||
|
||||
}//end processSingleLineArray()
|
||||
|
||||
|
||||
/**
|
||||
* Processes a multi-line array definition.
|
||||
*
|
||||
* @param \PHP_CodeSniffer\Files\File $phpcsFile The current file being checked.
|
||||
* @param int $stackPtr The position of the current token
|
||||
* in the stack passed in $tokens.
|
||||
* @param int $arrayStart The token that starts the array definition.
|
||||
* @param int $arrayEnd The token that ends the array definition.
|
||||
* @param array $indices An array of token positions for the array keys,
|
||||
* double arrows, and values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $arrayEnd, $indices)
|
||||
{
|
||||
$this->indicies = $indices;
|
||||
|
||||
}//end processMultiLineArray()
|
||||
|
||||
|
||||
}//end class
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/* testNoParentheses */
|
||||
$anonClass = new class {
|
||||
function __construct() {}
|
||||
};
|
||||
|
||||
/* testNoParenthesesAndEmptyTokens */
|
||||
$anonClass = new class // phpcs:ignore Standard.Cat
|
||||
{
|
||||
function __construct() {}
|
||||
};
|
||||
|
||||
/* testWithParentheses */
|
||||
$anonClass = new class() {};
|
||||
|
||||
/* testWithParenthesesAndEmptyTokens */
|
||||
$anonClass = new class /*comment */
|
||||
() {};
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the adding of the "parenthesis" keys to an anonymous class token.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class AnonClassParenthesisOwnerTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that anonymous class tokens without parenthesis do not get assigned a parenthesis owner.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataAnonClassNoParentheses
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAnonClassNoParentheses($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS);
|
||||
$this->assertFalse(array_key_exists('parenthesis_owner', $tokens[$anonClass]));
|
||||
$this->assertFalse(array_key_exists('parenthesis_opener', $tokens[$anonClass]));
|
||||
$this->assertFalse(array_key_exists('parenthesis_closer', $tokens[$anonClass]));
|
||||
|
||||
}//end testAnonClassNoParentheses()
|
||||
|
||||
|
||||
/**
|
||||
* Test that the next open/close parenthesis after an anonymous class without parenthesis
|
||||
* do not get assigned the anonymous class as a parenthesis owner.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataAnonClassNoParentheses
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAnonClassNoParenthesesNextOpenClose($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$function = $this->getTargetToken($testMarker, T_FUNCTION);
|
||||
|
||||
$opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS);
|
||||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener]));
|
||||
$this->assertSame($function, $tokens[$opener]['parenthesis_owner']);
|
||||
|
||||
$closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS);
|
||||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer]));
|
||||
$this->assertSame($function, $tokens[$closer]['parenthesis_owner']);
|
||||
|
||||
}//end testAnonClassNoParenthesesNextOpenClose()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testAnonClassNoParentheses()
|
||||
* @see testAnonClassNoParenthesesNextOpenClose()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataAnonClassNoParentheses()
|
||||
{
|
||||
return [
|
||||
['/* testNoParentheses */'],
|
||||
['/* testNoParenthesesAndEmptyTokens */'],
|
||||
];
|
||||
|
||||
}//end dataAnonClassNoParentheses()
|
||||
|
||||
|
||||
/**
|
||||
* Test that anonymous class tokens with parenthesis get assigned a parenthesis owner,
|
||||
* opener and closer; and that the opener/closer get the anonymous class assigned as owner.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataAnonClassWithParentheses
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAnonClassWithParentheses($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS);
|
||||
$opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS);
|
||||
$closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS);
|
||||
|
||||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$anonClass]));
|
||||
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$anonClass]));
|
||||
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$anonClass]));
|
||||
$this->assertSame($anonClass, $tokens[$anonClass]['parenthesis_owner']);
|
||||
$this->assertSame($opener, $tokens[$anonClass]['parenthesis_opener']);
|
||||
$this->assertSame($closer, $tokens[$anonClass]['parenthesis_closer']);
|
||||
|
||||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener]));
|
||||
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$opener]));
|
||||
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$opener]));
|
||||
$this->assertSame($anonClass, $tokens[$opener]['parenthesis_owner']);
|
||||
$this->assertSame($opener, $tokens[$opener]['parenthesis_opener']);
|
||||
$this->assertSame($closer, $tokens[$opener]['parenthesis_closer']);
|
||||
|
||||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer]));
|
||||
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$closer]));
|
||||
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$closer]));
|
||||
$this->assertSame($anonClass, $tokens[$closer]['parenthesis_owner']);
|
||||
$this->assertSame($opener, $tokens[$closer]['parenthesis_opener']);
|
||||
$this->assertSame($closer, $tokens[$closer]['parenthesis_closer']);
|
||||
|
||||
}//end testAnonClassWithParentheses()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testAnonClassWithParentheses()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataAnonClassWithParentheses()
|
||||
{
|
||||
return [
|
||||
['/* testWithParentheses */'],
|
||||
['/* testWithParenthesesAndEmptyTokens */'],
|
||||
];
|
||||
|
||||
}//end dataAnonClassWithParentheses()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/* testEmptyArray */
|
||||
$var = array();
|
||||
|
||||
/* testArrayWithSpace */
|
||||
$var = array (1 => 10);
|
||||
|
||||
/* testArrayWithComment */
|
||||
$var = Array /*comment*/ (1 => 10);
|
||||
|
||||
/* testNestingArray */
|
||||
$var = array(
|
||||
/* testNestedArray */
|
||||
array(
|
||||
'key' => 'value',
|
||||
|
||||
/* testClosureReturnType */
|
||||
'closure' => function($a) use($global) : Array {},
|
||||
),
|
||||
);
|
||||
|
||||
/* testFunctionDeclarationParamType */
|
||||
function foo(array $a) {}
|
||||
|
||||
/* testFunctionDeclarationReturnType */
|
||||
function foo($a) : int|array|null {}
|
||||
|
||||
class Bar {
|
||||
/* testClassConst */
|
||||
const ARRAY = [];
|
||||
|
||||
/* testClassMethod */
|
||||
public function array() {}
|
||||
}
|
||||
Vendored
+170
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests that the array keyword is tokenized correctly.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class ArrayKeywordTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that the array keyword is correctly tokenized as `T_ARRAY`.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent Optional. The token content to look for.
|
||||
*
|
||||
* @dataProvider dataArrayKeyword
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrayKeyword($testMarker, $testContent='array')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (code)');
|
||||
$this->assertSame('T_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (type)');
|
||||
|
||||
$this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set');
|
||||
$this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set');
|
||||
$this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set');
|
||||
|
||||
}//end testArrayKeyword()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testArrayKeyword()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataArrayKeyword()
|
||||
{
|
||||
return [
|
||||
'empty array' => ['/* testEmptyArray */'],
|
||||
'array with space before parenthesis' => ['/* testArrayWithSpace */'],
|
||||
'array with comment before parenthesis' => [
|
||||
'/* testArrayWithComment */',
|
||||
'Array',
|
||||
],
|
||||
'nested: outer array' => ['/* testNestingArray */'],
|
||||
'nested: inner array' => ['/* testNestedArray */'],
|
||||
];
|
||||
|
||||
}//end dataArrayKeyword()
|
||||
|
||||
|
||||
/**
|
||||
* Test that the array keyword when used in a type declaration is correctly tokenized as `T_STRING`.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent Optional. The token content to look for.
|
||||
*
|
||||
* @dataProvider dataArrayType
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrayType($testMarker, $testContent='array')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)');
|
||||
$this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)');
|
||||
|
||||
$this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set');
|
||||
|
||||
}//end testArrayType()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testArrayType()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataArrayType()
|
||||
{
|
||||
return [
|
||||
'closure return type' => [
|
||||
'/* testClosureReturnType */',
|
||||
'Array',
|
||||
],
|
||||
'function param type' => ['/* testFunctionDeclarationParamType */'],
|
||||
'function union return type' => ['/* testFunctionDeclarationReturnType */'],
|
||||
];
|
||||
|
||||
}//end dataArrayType()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the retokenization of `T_ARRAY` tokens to `T_STRING` is handled correctly
|
||||
* for tokens with the contents 'array' which aren't in actual fact the array keyword.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataNotArrayKeyword
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotArrayKeyword($testMarker, $testContent='array')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)');
|
||||
$this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)');
|
||||
|
||||
$this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set');
|
||||
|
||||
}//end testNotArrayKeyword()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNotArrayKeyword()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNotArrayKeyword()
|
||||
{
|
||||
return [
|
||||
'class-constant-name' => [
|
||||
'/* testClassConst */',
|
||||
'ARRAY',
|
||||
],
|
||||
'class-method-name' => ['/* testClassMethod */'],
|
||||
];
|
||||
|
||||
}//end dataNotArrayKeyword()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+90
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/* testAttribute */
|
||||
#[Attribute]
|
||||
class CustomAttribute {}
|
||||
|
||||
/* testAttributeWithParams */
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
class SecondCustomAttribute {}
|
||||
|
||||
/* testAttributeWithNamedParam */
|
||||
#[Attribute(flags: Attribute::TARGET_ALL)]
|
||||
class AttributeWithParams {
|
||||
public function __construct($foo, array $bar) {}
|
||||
}
|
||||
|
||||
/* testAttributeOnFunction */
|
||||
#[CustomAttribute]
|
||||
function attribute_on_function_test() {}
|
||||
|
||||
/* testAttributeOnFunctionWithParams */
|
||||
#[AttributeWithParams('foo', bar: ['bar' => 'foobar'])]
|
||||
function attribute_with_params_on_function_test() {}
|
||||
|
||||
/* testAttributeWithShortClosureParameter */
|
||||
#[AttributeWithParams(static fn ($value) => ! $value)]
|
||||
function attribute_with_short_closure_param_test() {}
|
||||
|
||||
/* testTwoAttributeOnTheSameLine */
|
||||
#[CustomAttribute] #[AttributeWithParams('foo')]
|
||||
function two_attribute_on_same_line_test() {}
|
||||
|
||||
/* testAttributeAndCommentOnTheSameLine */
|
||||
#[CustomAttribute] // This is a comment
|
||||
function attribute_and_line_comment_on_same_line_test() {}
|
||||
|
||||
/* testAttributeGrouping */
|
||||
#[CustomAttribute, AttributeWithParams('foo'), AttributeWithParams('foo', bar: ['bar' => 'foobar'])]
|
||||
function attribute_grouping_test() {}
|
||||
|
||||
/* testAttributeMultiline */
|
||||
#[
|
||||
CustomAttribute,
|
||||
AttributeWithParams('foo'),
|
||||
AttributeWithParams('foo', bar: ['bar' => 'foobar'])
|
||||
]
|
||||
function attribute_multiline_test() {}
|
||||
|
||||
/* testAttributeMultilineWithComment */
|
||||
#[
|
||||
CustomAttribute, // comment
|
||||
AttributeWithParams(/* another comment */ 'foo'),
|
||||
AttributeWithParams('foo', bar: ['bar' => 'foobar'])
|
||||
]
|
||||
function attribute_multiline_with_comment_test() {}
|
||||
|
||||
/* testSingleAttributeOnParameter */
|
||||
function single_attribute_on_parameter_test(#[ParamAttribute] int $param) {}
|
||||
|
||||
/* testMultipleAttributesOnParameter */
|
||||
function multiple_attributes_on_parameter_test(#[ParamAttribute, AttributeWithParams(/* another comment */ 'foo')] int $param) {}
|
||||
|
||||
/* testFqcnAttribute */
|
||||
#[Boo\QualifiedName, \Foo\FullyQualifiedName('foo')]
|
||||
function fqcn_attrebute_test() {}
|
||||
|
||||
/* testNestedAttributes */
|
||||
#[Boo\QualifiedName(fn (#[AttributeOne('boo')] $value) => (string) $value)]
|
||||
function nested_attributes_test() {}
|
||||
|
||||
/* testMultilineAttributesOnParameter */
|
||||
function multiline_attributes_on_parameter_test(#[
|
||||
AttributeWithParams(
|
||||
'foo'
|
||||
)
|
||||
] int $param) {}
|
||||
|
||||
/* testAttributeContainingTextLookingLikeCloseTag */
|
||||
#[DeprecationReason('reason: <https://some-website/reason?>')]
|
||||
function attribute_containing_text_looking_like_close_tag() {}
|
||||
|
||||
/* testAttributeContainingMultilineTextLookingLikeCloseTag */
|
||||
#[DeprecationReason(
|
||||
'reason: <https://some-website/reason?>'
|
||||
)]
|
||||
function attribute_containing_mulitline_text_looking_like_close_tag() {}
|
||||
|
||||
/* testInvalidAttribute */
|
||||
#[ThisIsNotAnAttribute
|
||||
function invalid_attribute_test() {}
|
||||
Vendored
+658
@@ -0,0 +1,658 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the support of PHP 8 attributes
|
||||
*
|
||||
* @author Alessandro Chitolina <alekitto@gmail.com>
|
||||
* @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class AttributesTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that attributes are parsed correctly.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param int $length The number of tokens between opener and closer.
|
||||
* @param array $tokenCodes The codes of tokens inside the attributes.
|
||||
*
|
||||
* @dataProvider dataAttribute
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAttribute($testMarker, $length, $tokenCodes)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE);
|
||||
$this->assertArrayHasKey('attribute_closer', $tokens[$attribute]);
|
||||
|
||||
$closer = $tokens[$attribute]['attribute_closer'];
|
||||
$this->assertSame(($attribute + $length), $closer);
|
||||
|
||||
$this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']);
|
||||
|
||||
$this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']);
|
||||
$this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']);
|
||||
|
||||
$map = array_map(
|
||||
function ($token) use ($attribute, $length) {
|
||||
$this->assertArrayHasKey('attribute_closer', $token);
|
||||
$this->assertSame(($attribute + $length), $token['attribute_closer']);
|
||||
|
||||
return $token['code'];
|
||||
},
|
||||
array_slice($tokens, ($attribute + 1), ($length - 1))
|
||||
);
|
||||
|
||||
$this->assertSame($tokenCodes, $map);
|
||||
|
||||
}//end testAttribute()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testAttribute()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataAttribute()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testAttribute */',
|
||||
2,
|
||||
[ T_STRING ],
|
||||
],
|
||||
[
|
||||
'/* testAttributeWithParams */',
|
||||
7,
|
||||
[
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_STRING,
|
||||
T_DOUBLE_COLON,
|
||||
T_STRING,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testAttributeWithNamedParam */',
|
||||
10,
|
||||
[
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_PARAM_NAME,
|
||||
T_COLON,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_DOUBLE_COLON,
|
||||
T_STRING,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testAttributeOnFunction */',
|
||||
2,
|
||||
[ T_STRING ],
|
||||
],
|
||||
[
|
||||
'/* testAttributeOnFunctionWithParams */',
|
||||
17,
|
||||
[
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_COMMA,
|
||||
T_WHITESPACE,
|
||||
T_PARAM_NAME,
|
||||
T_COLON,
|
||||
T_WHITESPACE,
|
||||
T_OPEN_SHORT_ARRAY,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_WHITESPACE,
|
||||
T_DOUBLE_ARROW,
|
||||
T_WHITESPACE,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_CLOSE_SHORT_ARRAY,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testAttributeWithShortClosureParameter */',
|
||||
17,
|
||||
[
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_STATIC,
|
||||
T_WHITESPACE,
|
||||
T_FN,
|
||||
T_WHITESPACE,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_VARIABLE,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
T_WHITESPACE,
|
||||
T_FN_ARROW,
|
||||
T_WHITESPACE,
|
||||
T_BOOLEAN_NOT,
|
||||
T_WHITESPACE,
|
||||
T_VARIABLE,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testAttributeGrouping */',
|
||||
26,
|
||||
[
|
||||
T_STRING,
|
||||
T_COMMA,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
T_COMMA,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_COMMA,
|
||||
T_WHITESPACE,
|
||||
T_PARAM_NAME,
|
||||
T_COLON,
|
||||
T_WHITESPACE,
|
||||
T_OPEN_SHORT_ARRAY,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_WHITESPACE,
|
||||
T_DOUBLE_ARROW,
|
||||
T_WHITESPACE,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_CLOSE_SHORT_ARRAY,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testAttributeMultiline */',
|
||||
31,
|
||||
[
|
||||
T_WHITESPACE,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_COMMA,
|
||||
T_WHITESPACE,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
T_COMMA,
|
||||
T_WHITESPACE,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_COMMA,
|
||||
T_WHITESPACE,
|
||||
T_PARAM_NAME,
|
||||
T_COLON,
|
||||
T_WHITESPACE,
|
||||
T_OPEN_SHORT_ARRAY,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_WHITESPACE,
|
||||
T_DOUBLE_ARROW,
|
||||
T_WHITESPACE,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_CLOSE_SHORT_ARRAY,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
T_WHITESPACE,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testFqcnAttribute */',
|
||||
13,
|
||||
[
|
||||
T_STRING,
|
||||
T_NS_SEPARATOR,
|
||||
T_STRING,
|
||||
T_COMMA,
|
||||
T_WHITESPACE,
|
||||
T_NS_SEPARATOR,
|
||||
T_STRING,
|
||||
T_NS_SEPARATOR,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataAttribute()
|
||||
|
||||
|
||||
/**
|
||||
* Test that multiple attributes on the same line are parsed correctly.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTwoAttributesOnTheSameLine()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$attribute = $this->getTargetToken('/* testTwoAttributeOnTheSameLine */', T_ATTRIBUTE);
|
||||
$this->assertArrayHasKey('attribute_closer', $tokens[$attribute]);
|
||||
|
||||
$closer = $tokens[$attribute]['attribute_closer'];
|
||||
$this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']);
|
||||
$this->assertSame(T_ATTRIBUTE, $tokens[($closer + 2)]['code']);
|
||||
$this->assertArrayHasKey('attribute_closer', $tokens[($closer + 2)]);
|
||||
|
||||
}//end testTwoAttributesOnTheSameLine()
|
||||
|
||||
|
||||
/**
|
||||
* Test that attribute followed by a line comment is parsed correctly.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAttributeAndLineComment()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$attribute = $this->getTargetToken('/* testAttributeAndCommentOnTheSameLine */', T_ATTRIBUTE);
|
||||
$this->assertArrayHasKey('attribute_closer', $tokens[$attribute]);
|
||||
|
||||
$closer = $tokens[$attribute]['attribute_closer'];
|
||||
$this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']);
|
||||
$this->assertSame(T_COMMENT, $tokens[($closer + 2)]['code']);
|
||||
|
||||
}//end testAttributeAndLineComment()
|
||||
|
||||
|
||||
/**
|
||||
* Test that attributes on function declaration parameters are parsed correctly.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param int $position The token position (starting from T_FUNCTION) of T_ATTRIBUTE token.
|
||||
* @param int $length The number of tokens between opener and closer.
|
||||
* @param array $tokenCodes The codes of tokens inside the attributes.
|
||||
*
|
||||
* @dataProvider dataAttributeOnParameters
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAttributeOnParameters($testMarker, $position, $length, array $tokenCodes)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$function = $this->getTargetToken($testMarker, T_FUNCTION);
|
||||
$attribute = ($function + $position);
|
||||
|
||||
$this->assertSame(T_ATTRIBUTE, $tokens[$attribute]['code']);
|
||||
$this->assertArrayHasKey('attribute_closer', $tokens[$attribute]);
|
||||
|
||||
$this->assertSame(($attribute + $length), $tokens[$attribute]['attribute_closer']);
|
||||
|
||||
$closer = $tokens[$attribute]['attribute_closer'];
|
||||
$this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']);
|
||||
$this->assertSame(T_STRING, $tokens[($closer + 2)]['code']);
|
||||
$this->assertSame('int', $tokens[($closer + 2)]['content']);
|
||||
|
||||
$this->assertSame(T_VARIABLE, $tokens[($closer + 4)]['code']);
|
||||
$this->assertSame('$param', $tokens[($closer + 4)]['content']);
|
||||
|
||||
$map = array_map(
|
||||
function ($token) use ($attribute, $length) {
|
||||
$this->assertArrayHasKey('attribute_closer', $token);
|
||||
$this->assertSame(($attribute + $length), $token['attribute_closer']);
|
||||
|
||||
return $token['code'];
|
||||
},
|
||||
array_slice($tokens, ($attribute + 1), ($length - 1))
|
||||
);
|
||||
|
||||
$this->assertSame($tokenCodes, $map);
|
||||
|
||||
}//end testAttributeOnParameters()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testAttributeOnParameters()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataAttributeOnParameters()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testSingleAttributeOnParameter */',
|
||||
4,
|
||||
2,
|
||||
[T_STRING],
|
||||
],
|
||||
[
|
||||
'/* testMultipleAttributesOnParameter */',
|
||||
4,
|
||||
10,
|
||||
[
|
||||
T_STRING,
|
||||
T_COMMA,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_COMMENT,
|
||||
T_WHITESPACE,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultilineAttributesOnParameter */',
|
||||
4,
|
||||
13,
|
||||
[
|
||||
T_WHITESPACE,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_WHITESPACE,
|
||||
T_WHITESPACE,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_WHITESPACE,
|
||||
T_WHITESPACE,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
T_WHITESPACE,
|
||||
T_WHITESPACE,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataAttributeOnParameters()
|
||||
|
||||
|
||||
/**
|
||||
* Test that an attribute containing text which looks like a PHP close tag is tokenized correctly.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param int $length The number of tokens between opener and closer.
|
||||
* @param array $expectedTokensAttribute The codes of tokens inside the attributes.
|
||||
* @param array $expectedTokensAfter The codes of tokens after the attributes.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute
|
||||
*
|
||||
* @dataProvider dataAttributeOnTextLookingLikeCloseTag
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAttributeContainingTextLookingLikeCloseTag($testMarker, $length, array $expectedTokensAttribute, array $expectedTokensAfter)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE);
|
||||
|
||||
$this->assertSame('T_ATTRIBUTE', $tokens[$attribute]['type']);
|
||||
$this->assertArrayHasKey('attribute_closer', $tokens[$attribute]);
|
||||
|
||||
$closer = $tokens[$attribute]['attribute_closer'];
|
||||
$this->assertSame(($attribute + $length), $closer);
|
||||
$this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']);
|
||||
$this->assertSame('T_ATTRIBUTE_END', $tokens[$closer]['type']);
|
||||
|
||||
$this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']);
|
||||
$this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']);
|
||||
|
||||
$i = ($attribute + 1);
|
||||
foreach ($expectedTokensAttribute as $item) {
|
||||
list($expectedType, $expectedContents) = $item;
|
||||
$this->assertSame($expectedType, $tokens[$i]['type']);
|
||||
$this->assertSame($expectedContents, $tokens[$i]['content']);
|
||||
$this->assertArrayHasKey('attribute_opener', $tokens[$i]);
|
||||
$this->assertArrayHasKey('attribute_closer', $tokens[$i]);
|
||||
++$i;
|
||||
}
|
||||
|
||||
$i = ($closer + 1);
|
||||
foreach ($expectedTokensAfter as $expectedCode) {
|
||||
$this->assertSame($expectedCode, $tokens[$i]['code']);
|
||||
++$i;
|
||||
}
|
||||
|
||||
}//end testAttributeContainingTextLookingLikeCloseTag()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see dataAttributeOnTextLookingLikeCloseTag()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataAttributeOnTextLookingLikeCloseTag()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testAttributeContainingTextLookingLikeCloseTag */',
|
||||
5,
|
||||
[
|
||||
[
|
||||
'T_STRING',
|
||||
'DeprecationReason',
|
||||
],
|
||||
[
|
||||
'T_OPEN_PARENTHESIS',
|
||||
'(',
|
||||
],
|
||||
[
|
||||
'T_CONSTANT_ENCAPSED_STRING',
|
||||
"'reason: <https://some-website/reason?>'",
|
||||
],
|
||||
[
|
||||
'T_CLOSE_PARENTHESIS',
|
||||
')',
|
||||
],
|
||||
[
|
||||
'T_ATTRIBUTE_END',
|
||||
']',
|
||||
],
|
||||
],
|
||||
[
|
||||
T_WHITESPACE,
|
||||
T_FUNCTION,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
T_WHITESPACE,
|
||||
T_OPEN_CURLY_BRACKET,
|
||||
T_CLOSE_CURLY_BRACKET,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testAttributeContainingMultilineTextLookingLikeCloseTag */',
|
||||
8,
|
||||
[
|
||||
[
|
||||
'T_STRING',
|
||||
'DeprecationReason',
|
||||
],
|
||||
[
|
||||
'T_OPEN_PARENTHESIS',
|
||||
'(',
|
||||
],
|
||||
[
|
||||
'T_WHITESPACE',
|
||||
"\n",
|
||||
],
|
||||
[
|
||||
'T_WHITESPACE',
|
||||
" ",
|
||||
],
|
||||
[
|
||||
'T_CONSTANT_ENCAPSED_STRING',
|
||||
"'reason: <https://some-website/reason?>'",
|
||||
],
|
||||
[
|
||||
'T_WHITESPACE',
|
||||
"\n",
|
||||
],
|
||||
[
|
||||
'T_CLOSE_PARENTHESIS',
|
||||
')',
|
||||
],
|
||||
[
|
||||
'T_ATTRIBUTE_END',
|
||||
']',
|
||||
],
|
||||
],
|
||||
[
|
||||
T_WHITESPACE,
|
||||
T_FUNCTION,
|
||||
T_WHITESPACE,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
T_WHITESPACE,
|
||||
T_OPEN_CURLY_BRACKET,
|
||||
T_CLOSE_CURLY_BRACKET,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataAttributeOnTextLookingLikeCloseTag()
|
||||
|
||||
|
||||
/**
|
||||
* Test that invalid attribute (or comment starting with #[ and without ]) are parsed correctly.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidAttribute()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$attribute = $this->getTargetToken('/* testInvalidAttribute */', T_ATTRIBUTE);
|
||||
|
||||
$this->assertArrayHasKey('attribute_closer', $tokens[$attribute]);
|
||||
$this->assertNull($tokens[$attribute]['attribute_closer']);
|
||||
|
||||
}//end testInvalidAttribute()
|
||||
|
||||
|
||||
/**
|
||||
* Test that nested attributes are parsed correctly.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedAttributes()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$tokenCodes = [
|
||||
T_STRING,
|
||||
T_NS_SEPARATOR,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_FN,
|
||||
T_WHITESPACE,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_ATTRIBUTE,
|
||||
T_STRING,
|
||||
T_OPEN_PARENTHESIS,
|
||||
T_CONSTANT_ENCAPSED_STRING,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
T_ATTRIBUTE_END,
|
||||
T_WHITESPACE,
|
||||
T_VARIABLE,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
T_WHITESPACE,
|
||||
T_FN_ARROW,
|
||||
T_WHITESPACE,
|
||||
T_STRING_CAST,
|
||||
T_WHITESPACE,
|
||||
T_VARIABLE,
|
||||
T_CLOSE_PARENTHESIS,
|
||||
];
|
||||
|
||||
$attribute = $this->getTargetToken('/* testNestedAttributes */', T_ATTRIBUTE);
|
||||
$this->assertArrayHasKey('attribute_closer', $tokens[$attribute]);
|
||||
|
||||
$closer = $tokens[$attribute]['attribute_closer'];
|
||||
$this->assertSame(($attribute + 24), $closer);
|
||||
|
||||
$this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']);
|
||||
|
||||
$this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']);
|
||||
$this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']);
|
||||
|
||||
$this->assertArrayNotHasKey('nested_attributes', $tokens[$attribute]);
|
||||
$this->assertArrayHasKey('nested_attributes', $tokens[($attribute + 8)]);
|
||||
$this->assertSame([$attribute => ($attribute + 24)], $tokens[($attribute + 8)]['nested_attributes']);
|
||||
|
||||
$test = function (array $tokens, $length, $nestedMap) use ($attribute) {
|
||||
foreach ($tokens as $token) {
|
||||
$this->assertArrayHasKey('attribute_closer', $token);
|
||||
$this->assertSame(($attribute + $length), $token['attribute_closer']);
|
||||
$this->assertSame($nestedMap, $token['nested_attributes']);
|
||||
}
|
||||
};
|
||||
|
||||
$test(array_slice($tokens, ($attribute + 1), 7), 24, [$attribute => $attribute + 24]);
|
||||
$test(array_slice($tokens, ($attribute + 8), 1), 8 + 5, [$attribute => $attribute + 24]);
|
||||
|
||||
// Length here is 8 (nested attribute offset) + 5 (real length).
|
||||
$test(
|
||||
array_slice($tokens, ($attribute + 9), 4),
|
||||
8 + 5,
|
||||
[
|
||||
$attribute => $attribute + 24,
|
||||
$attribute + 8 => $attribute + 13,
|
||||
]
|
||||
);
|
||||
|
||||
$test(array_slice($tokens, ($attribute + 13), 1), 8 + 5, [$attribute => $attribute + 24]);
|
||||
$test(array_slice($tokens, ($attribute + 14), 10), 24, [$attribute => $attribute + 24]);
|
||||
|
||||
$map = array_map(
|
||||
static function ($token) {
|
||||
return $token['code'];
|
||||
},
|
||||
array_slice($tokens, ($attribute + 1), 23)
|
||||
);
|
||||
|
||||
$this->assertSame($tokenCodes, $map);
|
||||
|
||||
}//end testNestedAttributes()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+95
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
/* testPureEnum */
|
||||
enum Foo
|
||||
{
|
||||
case SOME_CASE;
|
||||
}
|
||||
|
||||
/* testBackedIntEnum */
|
||||
enum Boo: int {
|
||||
case ONE = 1;
|
||||
case TWO = 1;
|
||||
}
|
||||
|
||||
/* testBackedStringEnum */
|
||||
enum Hoo : string
|
||||
{
|
||||
case ONE = 'one';
|
||||
case TWO = 'two';
|
||||
}
|
||||
|
||||
/* testComplexEnum */
|
||||
enum ComplexEnum: int implements SomeInterface
|
||||
{
|
||||
use SomeTrait {
|
||||
traitMethod as enumMethod;
|
||||
}
|
||||
|
||||
const SOME_CONSTANT = true;
|
||||
|
||||
case ONE = 1;
|
||||
|
||||
public function someMethod(): bool
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/* testEnumWithEnumAsClassName */
|
||||
enum /* testEnumAsClassNameAfterEnumKeyword */ Enum {}
|
||||
|
||||
/* testEnumIsCaseInsensitive */
|
||||
EnUm Enum {}
|
||||
|
||||
/* testEnumUsedAsClassName */
|
||||
class Enum {
|
||||
/* testEnumUsedAsClassConstantName */
|
||||
const ENUM = 'enum';
|
||||
|
||||
/* testEnumUsedAsMethodName */
|
||||
public function enum() {
|
||||
// Do something.
|
||||
|
||||
/* testEnumUsedAsPropertyName */
|
||||
$this->enum = 'foo';
|
||||
}
|
||||
}
|
||||
|
||||
/* testEnumUsedAsFunctionName */
|
||||
function enum()
|
||||
{
|
||||
}
|
||||
|
||||
/* testDeclarationContainingComment */
|
||||
enum /* comment */ Name
|
||||
{
|
||||
case SOME_CASE;
|
||||
}
|
||||
|
||||
enum /* testEnumUsedAsEnumName */ Enum
|
||||
{
|
||||
}
|
||||
|
||||
/* testEnumUsedAsNamespaceName */
|
||||
namespace Enum;
|
||||
/* testEnumUsedAsPartOfNamespaceName */
|
||||
namespace My\Enum\Collection;
|
||||
/* testEnumUsedInObjectInitialization */
|
||||
$obj = new Enum;
|
||||
/* testEnumAsFunctionCall */
|
||||
$var = enum($a, $b);
|
||||
/* testEnumAsFunctionCallWithNamespace */
|
||||
var = namespace\enum();
|
||||
/* testClassConstantFetchWithEnumAsClassName */
|
||||
echo Enum::CONSTANT;
|
||||
/* testClassConstantFetchWithEnumAsConstantName */
|
||||
echo ClassName::ENUM;
|
||||
|
||||
/* testParseErrorMissingName */
|
||||
enum {
|
||||
case SOME_CASE;
|
||||
}
|
||||
|
||||
/* testParseErrorLiveCoding */
|
||||
// This must be the last test in the file.
|
||||
enum
|
||||
Vendored
+229
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the support of PHP 8.1 "enum" keyword.
|
||||
*
|
||||
* @author Jaroslav Hanslík <kukulich@kukulich.cz>
|
||||
* @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class BackfillEnumTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that the "enum" keyword is tokenized as such.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param string $testContent The token content to look for.
|
||||
* @param int $openerOffset Offset to find expected scope opener.
|
||||
* @param int $closerOffset Offset to find expected scope closer.
|
||||
*
|
||||
* @dataProvider dataEnums
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEnums($testMarker, $testContent, $openerOffset, $closerOffset)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$enum = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent);
|
||||
|
||||
$this->assertSame(T_ENUM, $tokens[$enum]['code']);
|
||||
$this->assertSame('T_ENUM', $tokens[$enum]['type']);
|
||||
|
||||
$this->assertArrayHasKey('scope_condition', $tokens[$enum]);
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$enum]);
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$enum]);
|
||||
|
||||
$this->assertSame($enum, $tokens[$enum]['scope_condition']);
|
||||
|
||||
$scopeOpener = $tokens[$enum]['scope_opener'];
|
||||
$scopeCloser = $tokens[$enum]['scope_closer'];
|
||||
|
||||
$expectedScopeOpener = ($enum + $openerOffset);
|
||||
$expectedScopeCloser = ($enum + $closerOffset);
|
||||
|
||||
$this->assertSame($expectedScopeOpener, $scopeOpener);
|
||||
$this->assertArrayHasKey('scope_condition', $tokens[$scopeOpener]);
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$scopeOpener]);
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$scopeOpener]);
|
||||
$this->assertSame($enum, $tokens[$scopeOpener]['scope_condition']);
|
||||
$this->assertSame($scopeOpener, $tokens[$scopeOpener]['scope_opener']);
|
||||
$this->assertSame($scopeCloser, $tokens[$scopeOpener]['scope_closer']);
|
||||
|
||||
$this->assertSame($expectedScopeCloser, $scopeCloser);
|
||||
$this->assertArrayHasKey('scope_condition', $tokens[$scopeCloser]);
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$scopeCloser]);
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$scopeCloser]);
|
||||
$this->assertSame($enum, $tokens[$scopeCloser]['scope_condition']);
|
||||
$this->assertSame($scopeOpener, $tokens[$scopeCloser]['scope_opener']);
|
||||
$this->assertSame($scopeCloser, $tokens[$scopeCloser]['scope_closer']);
|
||||
|
||||
}//end testEnums()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testEnums()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataEnums()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testPureEnum */',
|
||||
'enum',
|
||||
4,
|
||||
12,
|
||||
],
|
||||
[
|
||||
'/* testBackedIntEnum */',
|
||||
'enum',
|
||||
7,
|
||||
29,
|
||||
],
|
||||
[
|
||||
'/* testBackedStringEnum */',
|
||||
'enum',
|
||||
8,
|
||||
30,
|
||||
],
|
||||
[
|
||||
'/* testComplexEnum */',
|
||||
'enum',
|
||||
11,
|
||||
72,
|
||||
],
|
||||
[
|
||||
'/* testEnumWithEnumAsClassName */',
|
||||
'enum',
|
||||
6,
|
||||
7,
|
||||
],
|
||||
[
|
||||
'/* testEnumIsCaseInsensitive */',
|
||||
'EnUm',
|
||||
4,
|
||||
5,
|
||||
],
|
||||
[
|
||||
'/* testDeclarationContainingComment */',
|
||||
'enum',
|
||||
6,
|
||||
14,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataEnums()
|
||||
|
||||
|
||||
/**
|
||||
* Test that "enum" when not used as the keyword is still tokenized as `T_STRING`.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataNotEnums
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotEnums($testMarker, $testContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$target = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent);
|
||||
$this->assertSame(T_STRING, $tokens[$target]['code']);
|
||||
$this->assertSame('T_STRING', $tokens[$target]['type']);
|
||||
|
||||
}//end testNotEnums()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNotEnums()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNotEnums()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testEnumAsClassNameAfterEnumKeyword */',
|
||||
'Enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumUsedAsClassName */',
|
||||
'Enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumUsedAsClassConstantName */',
|
||||
'ENUM',
|
||||
],
|
||||
[
|
||||
'/* testEnumUsedAsMethodName */',
|
||||
'enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumUsedAsPropertyName */',
|
||||
'enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumUsedAsFunctionName */',
|
||||
'enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumUsedAsEnumName */',
|
||||
'Enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumUsedAsNamespaceName */',
|
||||
'Enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumUsedAsPartOfNamespaceName */',
|
||||
'Enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumUsedInObjectInitialization */',
|
||||
'Enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumAsFunctionCall */',
|
||||
'enum',
|
||||
],
|
||||
[
|
||||
'/* testEnumAsFunctionCallWithNamespace */',
|
||||
'enum',
|
||||
],
|
||||
[
|
||||
'/* testClassConstantFetchWithEnumAsClassName */',
|
||||
'Enum',
|
||||
],
|
||||
[
|
||||
'/* testClassConstantFetchWithEnumAsConstantName */',
|
||||
'ENUM',
|
||||
],
|
||||
[
|
||||
'/* testParseErrorMissingName */',
|
||||
'enum',
|
||||
],
|
||||
[
|
||||
'/* testParseErrorLiveCoding */',
|
||||
'enum',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataNotEnums()
|
||||
|
||||
|
||||
}//end class
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/* testExplicitOctal */
|
||||
$foo = 0o137041;
|
||||
|
||||
/* testExplicitOctalCapitalised */
|
||||
$bar = 0O137041;
|
||||
|
||||
/* testExplicitOctalWithNumericSeparator */
|
||||
$octal = 0o137_041;
|
||||
|
||||
/* testInvalid1 */
|
||||
$foo = 0o_137;
|
||||
|
||||
/* testInvalid2 */
|
||||
$foo = 0O_41;
|
||||
|
||||
/* testInvalid3 */
|
||||
$foo = 0o91;
|
||||
|
||||
/* testInvalid4 */
|
||||
$foo = 0O282;
|
||||
|
||||
/* testInvalid5 */
|
||||
$foo = 0o28_2;
|
||||
|
||||
/* testInvalid6 */
|
||||
$foo = 0o2_82;
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the tokenization of explicit octal notation to PHP < 8.1.
|
||||
*
|
||||
* @author Mark Baker <mark@demon-angel.eu>
|
||||
* @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class BackfillExplicitOctalNotationTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that explicitly-defined octal values are tokenized as a single number and not as a number and a string.
|
||||
*
|
||||
* @param string $marker The comment which prefaces the target token in the test file.
|
||||
* @param string $value The expected content of the token
|
||||
* @param int|string $nextToken The expected next token.
|
||||
* @param string $nextContent The expected content of the next token.
|
||||
*
|
||||
* @dataProvider dataExplicitOctalNotation
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testExplicitOctalNotation($marker, $value, $nextToken, $nextContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$number = $this->getTargetToken($marker, [T_LNUMBER]);
|
||||
|
||||
$this->assertSame($value, $tokens[$number]['content'], 'Content of integer token does not match expectation');
|
||||
|
||||
$this->assertSame($nextToken, $tokens[($number + 1)]['code'], 'Next token is not the expected type, but '.$tokens[($number + 1)]['type']);
|
||||
$this->assertSame($nextContent, $tokens[($number + 1)]['content'], 'Next token did not have the expected contents');
|
||||
|
||||
}//end testExplicitOctalNotation()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testExplicitOctalNotation()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataExplicitOctalNotation()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'marker' => '/* testExplicitOctal */',
|
||||
'value' => '0o137041',
|
||||
'nextToken' => T_SEMICOLON,
|
||||
'nextContent' => ';',
|
||||
],
|
||||
[
|
||||
'marker' => '/* testExplicitOctalCapitalised */',
|
||||
'value' => '0O137041',
|
||||
'nextToken' => T_SEMICOLON,
|
||||
'nextContent' => ';',
|
||||
],
|
||||
[
|
||||
'marker' => '/* testExplicitOctalWithNumericSeparator */',
|
||||
'value' => '0o137_041',
|
||||
'nextToken' => T_SEMICOLON,
|
||||
'nextContent' => ';',
|
||||
],
|
||||
[
|
||||
'marker' => '/* testInvalid1 */',
|
||||
'value' => '0',
|
||||
'nextToken' => T_STRING,
|
||||
'nextContent' => 'o_137',
|
||||
],
|
||||
[
|
||||
'marker' => '/* testInvalid2 */',
|
||||
'value' => '0',
|
||||
'nextToken' => T_STRING,
|
||||
'nextContent' => 'O_41',
|
||||
],
|
||||
[
|
||||
'marker' => '/* testInvalid3 */',
|
||||
'value' => '0',
|
||||
'nextToken' => T_STRING,
|
||||
'nextContent' => 'o91',
|
||||
],
|
||||
[
|
||||
'marker' => '/* testInvalid4 */',
|
||||
'value' => '0O2',
|
||||
'nextToken' => T_LNUMBER,
|
||||
'nextContent' => '82',
|
||||
],
|
||||
[
|
||||
'marker' => '/* testInvalid5 */',
|
||||
'value' => '0o2',
|
||||
'nextToken' => T_LNUMBER,
|
||||
'nextContent' => '8_2',
|
||||
],
|
||||
[
|
||||
'marker' => '/* testInvalid6 */',
|
||||
'value' => '0o2',
|
||||
'nextToken' => T_STRING,
|
||||
'nextContent' => '_82',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataExplicitOctalNotation()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+198
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
/* testStandard */
|
||||
$fn1 = fn($x) => $x + $y;
|
||||
|
||||
/* testMixedCase */
|
||||
$fn1 = Fn($x) => $x + $y;
|
||||
|
||||
/* testWhitespace */
|
||||
$fn1 = fn ($x) => $x + $y;
|
||||
|
||||
/* testComment */
|
||||
$fn1 = fn /* comment here */ ($x) => $x + $y;
|
||||
|
||||
/* testHeredoc */
|
||||
$fn1 = fn() => <<<HTML
|
||||
fn
|
||||
HTML;
|
||||
|
||||
/* testFunctionName */
|
||||
function fn() {}
|
||||
|
||||
/* testNestedOuter */
|
||||
$fn = fn($x) => /* testNestedInner */ fn($y) => $x * $y + $z;
|
||||
|
||||
/* testNestedSharedCloserOuter */
|
||||
$foo = foo(fn() => /* testNestedSharedCloserInner */ fn() => bar() === true);
|
||||
|
||||
/* testFunctionCall */
|
||||
$extended = fn($c) => $callable($factory($c), $c);
|
||||
|
||||
/* testChainedFunctionCall */
|
||||
$result = Collection::from([1, 2])
|
||||
->map(fn($v) => $v * 2)
|
||||
->reduce(/* testFunctionArgument */ fn($tmp, $v) => $tmp + $v, 0);
|
||||
|
||||
/* testClosure */
|
||||
$extended = fn($c) => $callable(function() {
|
||||
for ($x = 1; $x < 10; $x++) {
|
||||
echo $x;
|
||||
}
|
||||
|
||||
echo 'done';
|
||||
}, $c);
|
||||
|
||||
/* testArrayIndex */
|
||||
$found = in_array_cb($needle, $haystack, fn($array, $needle) => $array[2] === $needle);
|
||||
|
||||
$result = array_map(
|
||||
/* testReturnType */
|
||||
static fn(int $number) : int => $number + 1,
|
||||
$numbers
|
||||
);
|
||||
|
||||
/* testReference */
|
||||
fn&($x) => $x;
|
||||
|
||||
/* testGrouped */
|
||||
(fn($x) => $x) + $y;
|
||||
|
||||
/* testArrayValue */
|
||||
$a = [
|
||||
'a' => fn() => return 1,
|
||||
];
|
||||
|
||||
/* testArrayValueNoTrailingComma */
|
||||
$a = [
|
||||
'a' => fn() => foo()
|
||||
];
|
||||
|
||||
/* testYield */
|
||||
$a = fn($x) => yield 'k' => $x;
|
||||
|
||||
/* testNullableNamespace */
|
||||
$a = fn(?\DateTime $x) : ?\DateTime => $x;
|
||||
|
||||
/* testNamespaceOperatorInTypes */
|
||||
$fn = fn(namespace\Foo $a) : ?namespace\Foo => $a;
|
||||
|
||||
/* testSelfReturnType */
|
||||
fn(self $a) : self => $a;
|
||||
|
||||
/* testParentReturnType */
|
||||
fn(parent $a) : parent => $a;
|
||||
|
||||
/* testCallableReturnType */
|
||||
fn(callable $a) : callable => $a;
|
||||
|
||||
/* testArrayReturnType */
|
||||
fn(array $a) : array => $a;
|
||||
|
||||
/* testStaticReturnType */
|
||||
fn(array $a) : static => $a;
|
||||
|
||||
/* testUnionParamType */
|
||||
$arrowWithUnionParam = fn(int|float $param) : SomeClass => new SomeClass($param);
|
||||
|
||||
/* testUnionReturnType */
|
||||
$arrowWithUnionReturn = fn($param) : int|float => $param | 10;
|
||||
|
||||
/* testTernary */
|
||||
$fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b';
|
||||
|
||||
/* testTernaryWithTypes */
|
||||
$fn = fn(int|null $a) : array|null => $a ? null : [];
|
||||
|
||||
function matchInArrow($x) {
|
||||
/* testWithMatchValue */
|
||||
$fn = fn($x) => match(true) {
|
||||
1, 2, 3, 4, 5 => 'foo',
|
||||
default => 'bar',
|
||||
};
|
||||
}
|
||||
|
||||
function matchInArrowAndMore($x) {
|
||||
/* testWithMatchValueAndMore */
|
||||
$fn = fn($x) => match(true) {
|
||||
1, 2, 3, 4, 5 => 'foo',
|
||||
default => 'bar',
|
||||
} . 'suffix';
|
||||
}
|
||||
|
||||
function arrowFunctionInMatchWithTrailingComma($x) {
|
||||
return match ($x) {
|
||||
/* testInMatchNotLastValue */
|
||||
1 => fn($y) => callMe($y),
|
||||
/* testInMatchLastValueWithTrailingComma */
|
||||
default => fn($y) => callThem($y),
|
||||
};
|
||||
}
|
||||
|
||||
function arrowFunctionInMatchNoTrailingComma1($x) {
|
||||
return match ($x) {
|
||||
1 => fn($y) => callMe($y),
|
||||
/* testInMatchLastValueNoTrailingComma1 */
|
||||
default => fn($y) => callThem($y)
|
||||
};
|
||||
}
|
||||
|
||||
function arrowFunctionInMatchNoTrailingComma2($x) {
|
||||
return match ($x) {
|
||||
/* testInMatchLastValueNoTrailingComma2 */
|
||||
default => fn($y) => 5 * $y
|
||||
};
|
||||
}
|
||||
|
||||
/* testConstantDeclaration */
|
||||
const FN = 'a';
|
||||
|
||||
/* testConstantDeclarationLower */
|
||||
const fn = 'a';
|
||||
|
||||
class Foo {
|
||||
/* testStaticMethodName */
|
||||
public static function fn($param) {
|
||||
/* testNestedInMethod */
|
||||
$fn = fn($c) => $callable($factory($c), $c);
|
||||
}
|
||||
|
||||
public function foo() {
|
||||
/* testPropertyAssignment */
|
||||
$this->fn = 'a';
|
||||
}
|
||||
}
|
||||
|
||||
$anon = new class() {
|
||||
/* testAnonClassMethodName */
|
||||
protected function fN($param) {
|
||||
}
|
||||
}
|
||||
|
||||
/* testNonArrowStaticMethodCall */
|
||||
$a = Foo::fn($param);
|
||||
|
||||
/* testNonArrowConstantAccess */
|
||||
$a = MyClass::FN;
|
||||
|
||||
/* testNonArrowConstantAccessMixed */
|
||||
$a = MyClass::Fn;
|
||||
|
||||
/* testNonArrowObjectMethodCall */
|
||||
$a = $obj->fn($param);
|
||||
|
||||
/* testNonArrowObjectMethodCallUpper */
|
||||
$a = $obj->FN($param);
|
||||
|
||||
/* testNonArrowNamespacedFunctionCall */
|
||||
$a = MyNS\Sub\Fn($param);
|
||||
|
||||
/* testNonArrowNamespaceOperatorFunctionCall */
|
||||
$a = namespace\fn($param);
|
||||
|
||||
/* testNonArrowFunctionNameWithUnionTypes */
|
||||
function fn(int|float $param) : string|null {}
|
||||
|
||||
/* testLiveCoding */
|
||||
// Intentional parse error. This has to be the last test in the file.
|
||||
$fn = fn
|
||||
Vendored
+802
@@ -0,0 +1,802 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the backfilling of the T_FN token to PHP < 7.4.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class BackfillFnTokenTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test simple arrow functions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSimple()
|
||||
{
|
||||
foreach (['/* testStandard */', '/* testMixedCase */'] as $comment) {
|
||||
$token = $this->getTargetToken($comment, T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 12);
|
||||
}
|
||||
|
||||
}//end testSimple()
|
||||
|
||||
|
||||
/**
|
||||
* Test whitespace inside arrow function definitions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testWhitespace()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testWhitespace */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 6, 13);
|
||||
|
||||
}//end testWhitespace()
|
||||
|
||||
|
||||
/**
|
||||
* Test comments inside arrow function definitions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testComment()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testComment */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 8, 15);
|
||||
|
||||
}//end testComment()
|
||||
|
||||
|
||||
/**
|
||||
* Test heredocs inside arrow function definitions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredoc()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testHeredoc */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 4, 9);
|
||||
|
||||
}//end testHeredoc()
|
||||
|
||||
|
||||
/**
|
||||
* Test nested arrow functions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedOuter()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testNestedOuter */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 25);
|
||||
|
||||
}//end testNestedOuter()
|
||||
|
||||
|
||||
/**
|
||||
* Test nested arrow functions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedInner()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testNestedInner */', T_FN);
|
||||
$this->backfillHelper($token, true);
|
||||
|
||||
$expectedScopeOpener = ($token + 5);
|
||||
$expectedScopeCloser = ($token + 16);
|
||||
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame(($token - 4), $tokens[$closer]['scope_opener'], 'Closer scope opener is not the arrow token of the "outer" arrow function (shared scope closer)');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//end testNestedInner()
|
||||
|
||||
|
||||
/**
|
||||
* Test nested arrow functions with a shared closer.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedSharedCloser()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testNestedSharedCloserOuter */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 4, 20);
|
||||
|
||||
$token = $this->getTargetToken('/* testNestedSharedCloserInner */', T_FN);
|
||||
$this->backfillHelper($token, true);
|
||||
|
||||
$expectedScopeOpener = ($token + 4);
|
||||
$expectedScopeCloser = ($token + 12);
|
||||
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for "inner" arrow function is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for "inner" arrow function is not the TRUE token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for "inner" arrow function is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for "inner" arrow function is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame(($token - 4), $tokens[$closer]['scope_opener'], 'Closer scope opener for "inner" arrow function is not the arrow token of the "outer" arrow function (shared scope closer)');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for "inner" arrow function is not the TRUE token');
|
||||
|
||||
}//end testNestedSharedCloser()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that call functions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFunctionCall()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testFunctionCall */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 17);
|
||||
|
||||
}//end testFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that are included in chained calls.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testChainedFunctionCall()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testChainedFunctionCall */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 12, 'bracket');
|
||||
|
||||
}//end testChainedFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that are used as function arguments.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFunctionArgument()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testFunctionArgument */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 8, 15, 'comma');
|
||||
|
||||
}//end testFunctionArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that use closures.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testClosure()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testClosure */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 60, 'comma');
|
||||
|
||||
}//end testClosure()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions using an array index.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrayIndex()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testArrayIndex */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 8, 17, 'comma');
|
||||
|
||||
}//end testArrayIndex()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions with a return type.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReturnType()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testReturnType */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 11, 18, 'comma');
|
||||
|
||||
}//end testReturnType()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that return a reference.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReference()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testReference */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 6, 9);
|
||||
|
||||
}//end testReference()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that are grouped by parenthesis.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGrouped()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testGrouped */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 8);
|
||||
|
||||
}//end testGrouped()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that are used as array values.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrayValue()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testArrayValue */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 4, 9, 'comma');
|
||||
|
||||
}//end testArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that are used as array values with no trailing comma.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrayValueNoTrailingComma()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testArrayValueNoTrailingComma */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 4, 8, 'closing parenthesis');
|
||||
|
||||
}//end testArrayValueNoTrailingComma()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that use the yield keyword.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testYield()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testYield */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 14);
|
||||
|
||||
}//end testYield()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that use nullable namespace types.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNullableNamespace()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testNullableNamespace */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 15, 18);
|
||||
|
||||
}//end testNullableNamespace()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that use the namespace operator in the return type.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNamespaceOperatorInTypes()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testNamespaceOperatorInTypes */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 16, 19);
|
||||
|
||||
}//end testNamespaceOperatorInTypes()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that use self/parent/callable/array/static return types.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testKeywordReturnTypes()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$testMarkers = [
|
||||
'Self',
|
||||
'Parent',
|
||||
'Callable',
|
||||
'Array',
|
||||
'Static',
|
||||
];
|
||||
|
||||
foreach ($testMarkers as $marker) {
|
||||
$token = $this->getTargetToken('/* test'.$marker.'ReturnType */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$expectedScopeOpener = ($token + 11);
|
||||
$expectedScopeCloser = ($token + 14);
|
||||
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], "Scope opener is not the arrow token (for $marker)");
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], "Scope closer is not the semicolon token(for $marker)");
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], "Opener scope opener is not the arrow token(for $marker)");
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], "Opener scope closer is not the semicolon token(for $marker)");
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], "Closer scope opener is not the arrow token(for $marker)");
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], "Closer scope closer is not the semicolon token(for $marker)");
|
||||
}
|
||||
|
||||
}//end testKeywordReturnTypes()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with a union parameter type.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUnionParamType()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testUnionParamType */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 13, 21);
|
||||
|
||||
}//end testUnionParamType()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function with a union return type.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUnionReturnType()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testUnionReturnType */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 11, 18);
|
||||
|
||||
}//end testUnionReturnType()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions used in ternary operators.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTernary()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testTernary */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 40);
|
||||
|
||||
$token = $this->getTargetToken('/* testTernaryThen */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$expectedScopeOpener = ($token + 8);
|
||||
$expectedScopeCloser = ($token + 12);
|
||||
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for THEN is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for THEN is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for THEN is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for THEN is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'Closer scope opener for THEN is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for THEN is not the semicolon token');
|
||||
|
||||
$token = $this->getTargetToken('/* testTernaryElse */', T_FN);
|
||||
$this->backfillHelper($token, true);
|
||||
|
||||
$expectedScopeOpener = ($token + 8);
|
||||
$expectedScopeCloser = ($token + 11);
|
||||
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for ELSE is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for ELSE is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for ELSE is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for ELSE is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame(($token - 24), $tokens[$closer]['scope_opener'], 'Closer scope opener for ELSE is not the arrow token of the "outer" arrow function (shared scope closer)');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for ELSE is not the semicolon token');
|
||||
|
||||
}//end testTernary()
|
||||
|
||||
|
||||
/**
|
||||
* Test typed arrow functions used in ternary operators.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTernaryWithTypes()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testTernaryWithTypes */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 15, 27);
|
||||
|
||||
}//end testTernaryWithTypes()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function returning a match control structure.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testWithMatchValue()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testWithMatchValue */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 44);
|
||||
|
||||
}//end testWithMatchValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function returning a match control structure with something behind it.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testWithMatchValueAndMore()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testWithMatchValueAndMore */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 48);
|
||||
|
||||
}//end testWithMatchValueAndMore()
|
||||
|
||||
|
||||
/**
|
||||
* Test match control structure returning arrow functions.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param int $openerOffset The expected offset of the scope opener in relation to the testMarker.
|
||||
* @param int $closerOffset The expected offset of the scope closer in relation to the testMarker.
|
||||
* @param string $expectedCloserType The type of token expected for the scope closer.
|
||||
* @param string $expectedCloserFriendlyName A friendly name for the type of token expected for the scope closer
|
||||
* to be used in the error message for failing tests.
|
||||
*
|
||||
* @dataProvider dataInMatchValue
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInMatchValue($testMarker, $openerOffset, $closerOffset, $expectedCloserType, $expectedCloserFriendlyName)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, $openerOffset, $closerOffset, $expectedCloserFriendlyName);
|
||||
|
||||
$this->assertSame($expectedCloserType, $tokens[($token + $closerOffset)]['type'], 'Mismatched scope closer type');
|
||||
|
||||
}//end testInMatchValue()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testInMatchValue()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataInMatchValue()
|
||||
{
|
||||
return [
|
||||
'not_last_value' => [
|
||||
'/* testInMatchNotLastValue */',
|
||||
5,
|
||||
11,
|
||||
'T_COMMA',
|
||||
'comma',
|
||||
],
|
||||
'last_value_with_trailing_comma' => [
|
||||
'/* testInMatchLastValueWithTrailingComma */',
|
||||
5,
|
||||
11,
|
||||
'T_COMMA',
|
||||
'comma',
|
||||
],
|
||||
'last_value_without_trailing_comma_1' => [
|
||||
'/* testInMatchLastValueNoTrailingComma1 */',
|
||||
5,
|
||||
10,
|
||||
'T_CLOSE_PARENTHESIS',
|
||||
'close parenthesis',
|
||||
],
|
||||
'last_value_without_trailing_comma_2' => [
|
||||
'/* testInMatchLastValueNoTrailingComma2 */',
|
||||
5,
|
||||
11,
|
||||
'T_VARIABLE',
|
||||
'$y variable',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataInMatchValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function nested within a method declaration.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedInMethod()
|
||||
{
|
||||
$token = $this->getTargetToken('/* testNestedInMethod */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
$this->scopePositionTestHelper($token, 5, 17);
|
||||
|
||||
}//end testNestedInMethod()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that "fn" keywords which are not arrow functions get tokenized as T_STRING and don't
|
||||
* have the extra token array indexes.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataNotAnArrowFunction
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotAnArrowFunction($testMarker, $testContent='fn')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_STRING, T_FN], $testContent);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING');
|
||||
|
||||
$this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set');
|
||||
$this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set');
|
||||
$this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set');
|
||||
|
||||
}//end testNotAnArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNotAnArrowFunction()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNotAnArrowFunction()
|
||||
{
|
||||
return [
|
||||
['/* testFunctionName */'],
|
||||
[
|
||||
'/* testConstantDeclaration */',
|
||||
'FN',
|
||||
],
|
||||
[
|
||||
'/* testConstantDeclarationLower */',
|
||||
'fn',
|
||||
],
|
||||
['/* testStaticMethodName */'],
|
||||
['/* testPropertyAssignment */'],
|
||||
[
|
||||
'/* testAnonClassMethodName */',
|
||||
'fN',
|
||||
],
|
||||
['/* testNonArrowStaticMethodCall */'],
|
||||
[
|
||||
'/* testNonArrowConstantAccess */',
|
||||
'FN',
|
||||
],
|
||||
[
|
||||
'/* testNonArrowConstantAccessMixed */',
|
||||
'Fn',
|
||||
],
|
||||
['/* testNonArrowObjectMethodCall */'],
|
||||
[
|
||||
'/* testNonArrowObjectMethodCallUpper */',
|
||||
'FN',
|
||||
],
|
||||
[
|
||||
'/* testNonArrowNamespacedFunctionCall */',
|
||||
'Fn',
|
||||
],
|
||||
['/* testNonArrowNamespaceOperatorFunctionCall */'],
|
||||
['/* testNonArrowFunctionNameWithUnionTypes */'],
|
||||
['/* testLiveCoding */'],
|
||||
];
|
||||
|
||||
}//end dataNotAnArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to check that all token keys are correctly set for T_FN tokens.
|
||||
*
|
||||
* @param int $token The T_FN token to check.
|
||||
* @param bool $skipScopeCloserCheck Whether to skip the scope closer check.
|
||||
* This should be set to "true" when testing nested arrow functions,
|
||||
* where the "inner" arrow function shares a scope closer with the
|
||||
* "outer" arrow function, as the 'scope_condition' for the scope closer
|
||||
* of the "inner" arrow function will point to the "outer" arrow function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function backfillHelper($token, $skipScopeCloserCheck=false)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$this->assertTrue(array_key_exists('scope_condition', $tokens[$token]), 'Scope condition is not set');
|
||||
$this->assertTrue(array_key_exists('scope_opener', $tokens[$token]), 'Scope opener is not set');
|
||||
$this->assertTrue(array_key_exists('scope_closer', $tokens[$token]), 'Scope closer is not set');
|
||||
$this->assertSame($tokens[$token]['scope_condition'], $token, 'Scope condition is not the T_FN token');
|
||||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$token]), 'Parenthesis owner is not set');
|
||||
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$token]), 'Parenthesis opener is not set');
|
||||
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$token]), 'Parenthesis closer is not set');
|
||||
$this->assertSame($tokens[$token]['parenthesis_owner'], $token, 'Parenthesis owner is not the T_FN token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertTrue(array_key_exists('scope_condition', $tokens[$opener]), 'Opener scope condition is not set');
|
||||
$this->assertTrue(array_key_exists('scope_opener', $tokens[$opener]), 'Opener scope opener is not set');
|
||||
$this->assertTrue(array_key_exists('scope_closer', $tokens[$opener]), 'Opener scope closer is not set');
|
||||
$this->assertSame($tokens[$opener]['scope_condition'], $token, 'Opener scope condition is not the T_FN token');
|
||||
$this->assertSame(T_FN_ARROW, $tokens[$opener]['code'], 'Arrow scope opener not tokenized as T_FN_ARROW (code)');
|
||||
$this->assertSame('T_FN_ARROW', $tokens[$opener]['type'], 'Arrow scope opener not tokenized as T_FN_ARROW (type)');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertTrue(array_key_exists('scope_condition', $tokens[$closer]), 'Closer scope condition is not set');
|
||||
$this->assertTrue(array_key_exists('scope_opener', $tokens[$closer]), 'Closer scope opener is not set');
|
||||
$this->assertTrue(array_key_exists('scope_closer', $tokens[$closer]), 'Closer scope closer is not set');
|
||||
if ($skipScopeCloserCheck === false) {
|
||||
$this->assertSame($tokens[$closer]['scope_condition'], $token, 'Closer scope condition is not the T_FN token');
|
||||
}
|
||||
|
||||
$opener = $tokens[$token]['parenthesis_opener'];
|
||||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener]), 'Opening parenthesis owner is not set');
|
||||
$this->assertSame($tokens[$opener]['parenthesis_owner'], $token, 'Opening parenthesis owner is not the T_FN token');
|
||||
|
||||
$closer = $tokens[$token]['parenthesis_closer'];
|
||||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer]), 'Closing parenthesis owner is not set');
|
||||
$this->assertSame($tokens[$closer]['parenthesis_owner'], $token, 'Closing parenthesis owner is not the T_FN token');
|
||||
|
||||
}//end backfillHelper()
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to check that the scope opener/closer positions are correctly set for T_FN tokens.
|
||||
*
|
||||
* @param int $token The T_FN token to check.
|
||||
* @param int $openerOffset The expected offset of the scope opener in relation to
|
||||
* the fn keyword.
|
||||
* @param int $closerOffset The expected offset of the scope closer in relation to
|
||||
* the fn keyword.
|
||||
* @param string $expectedCloserType Optional. The type of token expected for the scope closer.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function scopePositionTestHelper($token, $openerOffset, $closerOffset, $expectedCloserType='semicolon')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$expectedScopeOpener = ($token + $openerOffset);
|
||||
$expectedScopeCloser = ($token + $closerOffset);
|
||||
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer is not the '.$expectedCloserType.' token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer is not the '.$expectedCloserType.' token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer is not the '.$expectedCloserType.' token');
|
||||
|
||||
}//end scopePositionTestHelper()
|
||||
|
||||
|
||||
}//end class
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
|
||||
function simpleMatch($x) {
|
||||
/* testMatchSimple */
|
||||
return match ($x) {
|
||||
0 => 'Zero',
|
||||
1 => 'One',
|
||||
2 => 'Two',
|
||||
};
|
||||
}
|
||||
|
||||
function matchNoTrailingComma($bool) {
|
||||
/* testMatchNoTrailingComma */
|
||||
echo match ($bool) {
|
||||
true => "true\n",
|
||||
false => "false\n"
|
||||
};
|
||||
}
|
||||
|
||||
function matchWithDefault($i) {
|
||||
/* testMatchWithDefault */
|
||||
return match ($i) {
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
default => 'default',
|
||||
};
|
||||
}
|
||||
|
||||
function matchExpressionInCondition($i) {
|
||||
/* testMatchExpressionInCondition */
|
||||
return match (true) {
|
||||
$i >= 50 => '50+',
|
||||
$i >= 40 => '40-50',
|
||||
$i >= 30 => '30-40',
|
||||
$i >= 20 => '20-30',
|
||||
$i >= 10 => '10-20',
|
||||
default => '0-10',
|
||||
};
|
||||
}
|
||||
|
||||
function matchMultiCase($day) {
|
||||
/* testMatchMultiCase */
|
||||
return match ($day) {
|
||||
1, 7 => false,
|
||||
2, 3, 4, 5, 6 => true,
|
||||
};
|
||||
}
|
||||
|
||||
function matchMultiCaseTrailingCommaInCase($bool) {
|
||||
/* testMatchMultiCaseTrailingCommaInCase */
|
||||
echo match ($bool) {
|
||||
false,
|
||||
0,
|
||||
=> "false\n",
|
||||
true,
|
||||
1,
|
||||
=> "true\n",
|
||||
default,
|
||||
=> "not bool\n",
|
||||
};
|
||||
}
|
||||
|
||||
assert((function () {
|
||||
/* testMatchInClosureNotLowercase */
|
||||
Match ('foo') {
|
||||
'foo', 'bar' => false,
|
||||
'baz' => 'a',
|
||||
default => 'b',
|
||||
};
|
||||
})());
|
||||
|
||||
function matchInArrowFunction($x) {
|
||||
/* testMatchInArrowFunction */
|
||||
$fn = fn($x) => match(true) {
|
||||
1, 2, 3, 4, 5 => 'foo',
|
||||
default => 'bar',
|
||||
};
|
||||
}
|
||||
|
||||
function arrowFunctionInMatchNoTrailingComma($x) {
|
||||
/* testArrowFunctionInMatchNoTrailingComma */
|
||||
return match ($x) {
|
||||
1 => fn($y) => callMe($y),
|
||||
default => fn($y) => callThem($y)
|
||||
};
|
||||
}
|
||||
|
||||
/* testMatchInFunctionCallParamNotLowercase */
|
||||
var_dump(MATCH ( 'foo' ) {
|
||||
'foo' => dump_and_return('foo'),
|
||||
'bar' => dump_and_return('bar'),
|
||||
});
|
||||
|
||||
/* testMatchInMethodCallParam */
|
||||
Test::usesValue(match(true) { true => $i });
|
||||
|
||||
/* testMatchDiscardResult */
|
||||
match (1) {
|
||||
1 => print "Executed\n",
|
||||
};
|
||||
|
||||
/* testMatchWithDuplicateConditionsWithComments */
|
||||
echo match /*comment*/ ( $value /*comment*/ ) {
|
||||
// Comment.
|
||||
2, 1 => '2, 1',
|
||||
1 => 1,
|
||||
3 => 3,
|
||||
4 => 4,
|
||||
5 => 5,
|
||||
};
|
||||
|
||||
/* testNestedMatchOuter */
|
||||
$x = match ($y) {
|
||||
/* testNestedMatchInner */
|
||||
default => match ($z) { 1 => 1 },
|
||||
};
|
||||
|
||||
/* testMatchInTernaryCondition */
|
||||
$x = match ($test) { 1 => 'a', 2 => 'b' } ?
|
||||
/* testMatchInTernaryThen */ match ($test) { 1 => 'a', 2 => 'b' } :
|
||||
/* testMatchInTernaryElse */ match ($notTest) { 3 => 'a', 4 => 'b' };
|
||||
|
||||
/* testMatchInArrayValue */
|
||||
$array = array(
|
||||
match ($test) { 1 => 'a', 2 => 'b' },
|
||||
);
|
||||
|
||||
/* testMatchInArrayKey */
|
||||
$array = [
|
||||
match ($test) { 1 => 'a', 2 => 'b' } => 'dynamic keys, woho!',
|
||||
];
|
||||
|
||||
/* testMatchreturningArray */
|
||||
$matcher = match ($x) {
|
||||
0 => array( 0 => 1, 'a' => 2, 'b' => 3 ),
|
||||
1 => [1, 2, 3],
|
||||
2 => array( 1, [1, 2, 3], 2, 3),
|
||||
3 => [ 0 => 1, 'a' => array(1, 2, 3), 'b' => 2, 3],
|
||||
};
|
||||
|
||||
/* testSwitchContainingMatch */
|
||||
switch ($something) {
|
||||
/* testMatchWithDefaultNestedInSwitchCase1 */
|
||||
case 'foo':
|
||||
$var = [1, 2, 3];
|
||||
$var = match ($i) {
|
||||
1 => 1,
|
||||
default => 'default',
|
||||
};
|
||||
continue 2;
|
||||
|
||||
/* testMatchWithDefaultNestedInSwitchCase2 */
|
||||
case 'bar' ;
|
||||
$i = callMe($a, $b);
|
||||
return match ($i) {
|
||||
1 => 1,
|
||||
default => 'default',
|
||||
};
|
||||
|
||||
/* testMatchWithDefaultNestedInSwitchDefault */
|
||||
default:
|
||||
echo 'something', match ($i) {
|
||||
1 => 1,
|
||||
default => 'default',
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
/* testMatchContainingSwitch */
|
||||
$x = match ($y) {
|
||||
5, 8 => function($z) {
|
||||
/* testSwitchNestedInMatch1 */
|
||||
switch($z) {
|
||||
case 'a':
|
||||
$var = [1, 2, 3];
|
||||
return 'a';
|
||||
/* testSwitchDefaultNestedInMatchCase */
|
||||
default:
|
||||
$i = callMe($a, $b);
|
||||
return 'default1';
|
||||
}
|
||||
},
|
||||
default => function($z) {
|
||||
/* testSwitchNestedInMatch2 */
|
||||
switch($z) {
|
||||
case 'a';
|
||||
$i = callMe($a, $b);
|
||||
return 'b';
|
||||
/* testSwitchDefaultNestedInMatchDefault */
|
||||
default;
|
||||
$var = [1, 2, 3];
|
||||
return 'default2';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* testMatchNoCases */
|
||||
// Intentional fatal error.
|
||||
$x = match (true) {};
|
||||
|
||||
/* testMatchMultiDefault */
|
||||
// Intentional fatal error.
|
||||
echo match (1) {
|
||||
default => 'foo',
|
||||
1 => 'bar',
|
||||
2 => 'baz',
|
||||
default => 'qux',
|
||||
};
|
||||
|
||||
/* testNoMatchStaticMethodCall */
|
||||
$a = Foo::match($param);
|
||||
|
||||
/* testNoMatchClassConstantAccess */
|
||||
$a = MyClass::MATCH;
|
||||
|
||||
/* testNoMatchClassConstantArrayAccessMixedCase */
|
||||
$a = MyClass::Match[$a];
|
||||
|
||||
/* testNoMatchMethodCall */
|
||||
$a = $obj->match($param);
|
||||
|
||||
/* testNoMatchMethodCallUpper */
|
||||
$a = $obj??->MATCH()->chain($param);
|
||||
|
||||
/* testNoMatchPropertyAccess */
|
||||
$a = $obj->match;
|
||||
|
||||
/* testNoMatchNamespacedFunctionCall */
|
||||
// Intentional fatal error.
|
||||
$a = MyNS\Sub\match($param);
|
||||
|
||||
/* testNoMatchNamespaceOperatorFunctionCall */
|
||||
// Intentional fatal error.
|
||||
$a = namespace\match($param);
|
||||
|
||||
interface MatchInterface {
|
||||
/* testNoMatchInterfaceMethodDeclaration */
|
||||
public static function match($param);
|
||||
}
|
||||
|
||||
class MatchClass {
|
||||
/* testNoMatchClassConstantDeclarationLower */
|
||||
const match = 'a';
|
||||
|
||||
/* testNoMatchClassMethodDeclaration */
|
||||
public static function match($param) {
|
||||
/* testNoMatchPropertyAssignment */
|
||||
$this->match = 'a';
|
||||
}
|
||||
}
|
||||
|
||||
/* testNoMatchClassInstantiation */
|
||||
$obj = new Match();
|
||||
|
||||
$anon = new class() {
|
||||
/* testNoMatchAnonClassMethodDeclaration */
|
||||
protected function maTCH($param) {
|
||||
}
|
||||
};
|
||||
|
||||
/* testNoMatchClassDeclaration */
|
||||
// Intentional fatal error. Match is now a reserved keyword.
|
||||
class Match {}
|
||||
|
||||
/* testNoMatchInterfaceDeclaration */
|
||||
// Intentional fatal error. Match is now a reserved keyword.
|
||||
interface Match {}
|
||||
|
||||
/* testNoMatchTraitDeclaration */
|
||||
// Intentional fatal error. Match is now a reserved keyword.
|
||||
trait Match {}
|
||||
|
||||
/* testNoMatchConstantDeclaration */
|
||||
// Intentional fatal error. Match is now a reserved keyword.
|
||||
const MATCH = '1';
|
||||
|
||||
/* testNoMatchFunctionDeclaration */
|
||||
// Intentional fatal error. Match is now a reserved keyword.
|
||||
function match() {}
|
||||
|
||||
/* testNoMatchNamespaceDeclaration */
|
||||
// Intentional fatal error. Match is now a reserved keyword.
|
||||
namespace Match {}
|
||||
|
||||
/* testNoMatchExtendedClassDeclaration */
|
||||
// Intentional fatal error. Match is now a reserved keyword.
|
||||
class Foo extends Match {}
|
||||
|
||||
/* testNoMatchImplementedClassDeclaration */
|
||||
// Intentional fatal error. Match is now a reserved keyword.
|
||||
class Bar implements Match {}
|
||||
|
||||
/* testNoMatchInUseStatement */
|
||||
// Intentional fatal error in PHP < 8. Match is now a reserved keyword.
|
||||
use Match\me;
|
||||
|
||||
function brokenMatchNoCurlies($x) {
|
||||
/* testNoMatchMissingCurlies */
|
||||
// Intentional fatal error. New control structure is not supported without curly braces.
|
||||
return match ($x)
|
||||
0 => 'Zero',
|
||||
1 => 'One',
|
||||
2 => 'Two',
|
||||
;
|
||||
}
|
||||
|
||||
function brokenMatchAlternativeSyntax($x) {
|
||||
/* testNoMatchAlternativeSyntax */
|
||||
// Intentional fatal error. Alternative syntax is not supported.
|
||||
return match ($x) :
|
||||
0 => 'Zero',
|
||||
1 => 'One',
|
||||
2 => 'Two',
|
||||
endmatch;
|
||||
}
|
||||
|
||||
/* testLiveCoding */
|
||||
// Intentional parse error. This has to be the last test in the file.
|
||||
echo match
|
||||
+529
@@ -0,0 +1,529 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the backfilling of the T_MATCH token to PHP < 8.0, as well as the
|
||||
* setting of parenthesis/scopes for match control structures across PHP versions.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
|
||||
class BackfillMatchTokenTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test tokenization of match expressions.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param int $openerOffset The expected offset of the scope opener in relation to the testMarker.
|
||||
* @param int $closerOffset The expected offset of the scope closer in relation to the testMarker.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataMatchExpression
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchExpression($testMarker, $openerOffset, $closerOffset, $testContent='match')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_MATCH, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH (code)');
|
||||
$this->assertSame('T_MATCH', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH (type)');
|
||||
|
||||
$this->scopeTestHelper($token, $openerOffset, $closerOffset);
|
||||
$this->parenthesisTestHelper($token);
|
||||
|
||||
}//end testMatchExpression()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testMatchExpression()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataMatchExpression()
|
||||
{
|
||||
return [
|
||||
'simple_match' => [
|
||||
'/* testMatchSimple */',
|
||||
6,
|
||||
33,
|
||||
],
|
||||
'no_trailing_comma' => [
|
||||
'/* testMatchNoTrailingComma */',
|
||||
6,
|
||||
24,
|
||||
],
|
||||
'with_default_case' => [
|
||||
'/* testMatchWithDefault */',
|
||||
6,
|
||||
33,
|
||||
],
|
||||
'expression_in_condition' => [
|
||||
'/* testMatchExpressionInCondition */',
|
||||
6,
|
||||
77,
|
||||
],
|
||||
'multicase' => [
|
||||
'/* testMatchMultiCase */',
|
||||
6,
|
||||
40,
|
||||
],
|
||||
'multicase_trailing_comma_in_case' => [
|
||||
'/* testMatchMultiCaseTrailingCommaInCase */',
|
||||
6,
|
||||
47,
|
||||
],
|
||||
'in_closure_not_lowercase' => [
|
||||
'/* testMatchInClosureNotLowercase */',
|
||||
6,
|
||||
36,
|
||||
'Match',
|
||||
],
|
||||
'in_arrow_function' => [
|
||||
'/* testMatchInArrowFunction */',
|
||||
5,
|
||||
36,
|
||||
],
|
||||
'arrow_function_in_match_no_trailing_comma' => [
|
||||
'/* testArrowFunctionInMatchNoTrailingComma */',
|
||||
6,
|
||||
44,
|
||||
],
|
||||
'in_function_call_param_not_lowercase' => [
|
||||
'/* testMatchInFunctionCallParamNotLowercase */',
|
||||
8,
|
||||
32,
|
||||
'MATCH',
|
||||
],
|
||||
'in_method_call_param' => [
|
||||
'/* testMatchInMethodCallParam */',
|
||||
5,
|
||||
13,
|
||||
],
|
||||
'discard_result' => [
|
||||
'/* testMatchDiscardResult */',
|
||||
6,
|
||||
18,
|
||||
],
|
||||
'duplicate_conditions_and_comments' => [
|
||||
'/* testMatchWithDuplicateConditionsWithComments */',
|
||||
12,
|
||||
59,
|
||||
],
|
||||
'nested_match_outer' => [
|
||||
'/* testNestedMatchOuter */',
|
||||
6,
|
||||
33,
|
||||
],
|
||||
'nested_match_inner' => [
|
||||
'/* testNestedMatchInner */',
|
||||
6,
|
||||
14,
|
||||
],
|
||||
'ternary_condition' => [
|
||||
'/* testMatchInTernaryCondition */',
|
||||
6,
|
||||
21,
|
||||
],
|
||||
'ternary_then' => [
|
||||
'/* testMatchInTernaryThen */',
|
||||
6,
|
||||
21,
|
||||
],
|
||||
'ternary_else' => [
|
||||
'/* testMatchInTernaryElse */',
|
||||
6,
|
||||
21,
|
||||
],
|
||||
'array_value' => [
|
||||
'/* testMatchInArrayValue */',
|
||||
6,
|
||||
21,
|
||||
],
|
||||
'array_key' => [
|
||||
'/* testMatchInArrayKey */',
|
||||
6,
|
||||
21,
|
||||
],
|
||||
'returning_array' => [
|
||||
'/* testMatchreturningArray */',
|
||||
6,
|
||||
125,
|
||||
],
|
||||
'nested_in_switch_case_1' => [
|
||||
'/* testMatchWithDefaultNestedInSwitchCase1 */',
|
||||
6,
|
||||
25,
|
||||
],
|
||||
'nested_in_switch_case_2' => [
|
||||
'/* testMatchWithDefaultNestedInSwitchCase2 */',
|
||||
6,
|
||||
25,
|
||||
],
|
||||
'nested_in_switch_default' => [
|
||||
'/* testMatchWithDefaultNestedInSwitchDefault */',
|
||||
6,
|
||||
25,
|
||||
],
|
||||
'match_with_nested_switch' => [
|
||||
'/* testMatchContainingSwitch */',
|
||||
6,
|
||||
180,
|
||||
],
|
||||
'no_cases' => [
|
||||
'/* testMatchNoCases */',
|
||||
6,
|
||||
7,
|
||||
],
|
||||
'multi_default' => [
|
||||
'/* testMatchMultiDefault */',
|
||||
6,
|
||||
40,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataMatchExpression()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that "match" keywords which are not match control structures get tokenized as T_STRING
|
||||
* and don't have the extra token array indexes.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataNotAMatchStructure
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotAMatchStructure($testMarker, $testContent='match')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)');
|
||||
$this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)');
|
||||
|
||||
$this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set');
|
||||
$this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set');
|
||||
$this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set');
|
||||
$this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set');
|
||||
|
||||
$next = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($token + 1), null, true);
|
||||
if ($next !== false && $tokens[$next]['code'] === T_OPEN_PARENTHESIS) {
|
||||
$this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set for opener after');
|
||||
}
|
||||
|
||||
}//end testNotAMatchStructure()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNotAMatchStructure()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNotAMatchStructure()
|
||||
{
|
||||
return [
|
||||
'static_method_call' => ['/* testNoMatchStaticMethodCall */'],
|
||||
'class_constant_access' => [
|
||||
'/* testNoMatchClassConstantAccess */',
|
||||
'MATCH',
|
||||
],
|
||||
'class_constant_array_access' => [
|
||||
'/* testNoMatchClassConstantArrayAccessMixedCase */',
|
||||
'Match',
|
||||
],
|
||||
'method_call' => ['/* testNoMatchMethodCall */'],
|
||||
'method_call_uppercase' => [
|
||||
'/* testNoMatchMethodCallUpper */',
|
||||
'MATCH',
|
||||
],
|
||||
'property_access' => ['/* testNoMatchPropertyAccess */'],
|
||||
'namespaced_function_call' => ['/* testNoMatchNamespacedFunctionCall */'],
|
||||
'namespace_operator_function_call' => ['/* testNoMatchNamespaceOperatorFunctionCall */'],
|
||||
'interface_method_declaration' => ['/* testNoMatchInterfaceMethodDeclaration */'],
|
||||
'class_constant_declaration' => ['/* testNoMatchClassConstantDeclarationLower */'],
|
||||
'class_method_declaration' => ['/* testNoMatchClassMethodDeclaration */'],
|
||||
'property_assigment' => ['/* testNoMatchPropertyAssignment */'],
|
||||
'class_instantiation' => [
|
||||
'/* testNoMatchClassInstantiation */',
|
||||
'Match',
|
||||
],
|
||||
'anon_class_method_declaration' => [
|
||||
'/* testNoMatchAnonClassMethodDeclaration */',
|
||||
'maTCH',
|
||||
],
|
||||
'class_declaration' => [
|
||||
'/* testNoMatchClassDeclaration */',
|
||||
'Match',
|
||||
],
|
||||
'interface_declaration' => [
|
||||
'/* testNoMatchInterfaceDeclaration */',
|
||||
'Match',
|
||||
],
|
||||
'trait_declaration' => [
|
||||
'/* testNoMatchTraitDeclaration */',
|
||||
'Match',
|
||||
],
|
||||
'constant_declaration' => [
|
||||
'/* testNoMatchConstantDeclaration */',
|
||||
'MATCH',
|
||||
],
|
||||
'function_declaration' => ['/* testNoMatchFunctionDeclaration */'],
|
||||
'namespace_declaration' => [
|
||||
'/* testNoMatchNamespaceDeclaration */',
|
||||
'Match',
|
||||
],
|
||||
'class_extends_declaration' => [
|
||||
'/* testNoMatchExtendedClassDeclaration */',
|
||||
'Match',
|
||||
],
|
||||
'class_implements_declaration' => [
|
||||
'/* testNoMatchImplementedClassDeclaration */',
|
||||
'Match',
|
||||
],
|
||||
'use_statement' => [
|
||||
'/* testNoMatchInUseStatement */',
|
||||
'Match',
|
||||
],
|
||||
'unsupported_inline_control_structure' => ['/* testNoMatchMissingCurlies */'],
|
||||
'unsupported_alternative_syntax' => ['/* testNoMatchAlternativeSyntax */'],
|
||||
'live_coding' => ['/* testLiveCoding */'],
|
||||
];
|
||||
|
||||
}//end dataNotAMatchStructure()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the tokenization of switch structures is not affected by the backfill.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param int $openerOffset The expected offset of the scope opener in relation to the testMarker.
|
||||
* @param int $closerOffset The expected offset of the scope closer in relation to the testMarker.
|
||||
*
|
||||
* @dataProvider dataSwitchExpression
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSwitchExpression($testMarker, $openerOffset, $closerOffset)
|
||||
{
|
||||
$token = $this->getTargetToken($testMarker, T_SWITCH);
|
||||
|
||||
$this->scopeTestHelper($token, $openerOffset, $closerOffset);
|
||||
$this->parenthesisTestHelper($token);
|
||||
|
||||
}//end testSwitchExpression()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testSwitchExpression()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataSwitchExpression()
|
||||
{
|
||||
return [
|
||||
'switch_containing_match' => [
|
||||
'/* testSwitchContainingMatch */',
|
||||
6,
|
||||
174,
|
||||
],
|
||||
'match_containing_switch_1' => [
|
||||
'/* testSwitchNestedInMatch1 */',
|
||||
5,
|
||||
63,
|
||||
],
|
||||
'match_containing_switch_2' => [
|
||||
'/* testSwitchNestedInMatch2 */',
|
||||
5,
|
||||
63,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataSwitchExpression()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the tokenization of a switch case/default structure containing a match structure
|
||||
* or contained *in* a match structure is not affected by the backfill.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param int $openerOffset The expected offset of the scope opener in relation to the testMarker.
|
||||
* @param int $closerOffset The expected offset of the scope closer in relation to the testMarker.
|
||||
*
|
||||
* @dataProvider dataSwitchCaseVersusMatch
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSwitchCaseVersusMatch($testMarker, $openerOffset, $closerOffset)
|
||||
{
|
||||
$token = $this->getTargetToken($testMarker, [T_CASE, T_DEFAULT]);
|
||||
|
||||
$this->scopeTestHelper($token, $openerOffset, $closerOffset);
|
||||
|
||||
}//end testSwitchCaseVersusMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testSwitchCaseVersusMatch()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataSwitchCaseVersusMatch()
|
||||
{
|
||||
return [
|
||||
'switch_with_nested_match_case_1' => [
|
||||
'/* testMatchWithDefaultNestedInSwitchCase1 */',
|
||||
3,
|
||||
55,
|
||||
],
|
||||
'switch_with_nested_match_case_2' => [
|
||||
'/* testMatchWithDefaultNestedInSwitchCase2 */',
|
||||
4,
|
||||
21,
|
||||
],
|
||||
'switch_with_nested_match_default_case' => [
|
||||
'/* testMatchWithDefaultNestedInSwitchDefault */',
|
||||
1,
|
||||
38,
|
||||
],
|
||||
'match_with_nested_switch_case' => [
|
||||
'/* testSwitchDefaultNestedInMatchCase */',
|
||||
1,
|
||||
18,
|
||||
],
|
||||
'match_with_nested_switch_default_case' => [
|
||||
'/* testSwitchDefaultNestedInMatchDefault */',
|
||||
1,
|
||||
20,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataSwitchCaseVersusMatch()
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to verify that all scope related array indexes for a control structure
|
||||
* are set correctly.
|
||||
*
|
||||
* @param string $token The control structure token to check.
|
||||
* @param int $openerOffset The expected offset of the scope opener in relation to
|
||||
* the control structure token.
|
||||
* @param int $closerOffset The expected offset of the scope closer in relation to
|
||||
* the control structure token.
|
||||
* @param bool $skipScopeCloserCheck Whether to skip the scope closer check.
|
||||
* This should be set to "true" when testing nested arrow functions,
|
||||
* where the "inner" arrow function shares a scope closer with the
|
||||
* "outer" arrow function, as the 'scope_condition' for the scope closer
|
||||
* of the "inner" arrow function will point to the "outer" arrow function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function scopeTestHelper($token, $openerOffset, $closerOffset, $skipScopeCloserCheck=false)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$tokenArray = $tokens[$token];
|
||||
$tokenType = $tokenArray['type'];
|
||||
$expectedScopeOpener = ($token + $openerOffset);
|
||||
$expectedScopeCloser = ($token + $closerOffset);
|
||||
|
||||
$this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set');
|
||||
$this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set');
|
||||
$this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set');
|
||||
$this->assertSame($token, $tokenArray['scope_condition'], 'Scope condition is not the '.$tokenType.' token');
|
||||
$this->assertSame($expectedScopeOpener, $tokenArray['scope_opener'], 'Scope opener of the '.$tokenType.' token incorrect');
|
||||
$this->assertSame($expectedScopeCloser, $tokenArray['scope_closer'], 'Scope closer of the '.$tokenType.' token incorrect');
|
||||
|
||||
$opener = $tokenArray['scope_opener'];
|
||||
$this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set');
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set');
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set');
|
||||
$this->assertSame($token, $tokens[$opener]['scope_condition'], 'Opener scope condition is not the '.$tokenType.' token');
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], $tokenType.' opener scope opener token incorrect');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], $tokenType.' opener scope closer token incorrect');
|
||||
|
||||
$closer = $tokenArray['scope_closer'];
|
||||
$this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set');
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set');
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set');
|
||||
if ($skipScopeCloserCheck === false) {
|
||||
$this->assertSame($token, $tokens[$closer]['scope_condition'], 'Closer scope condition is not the '.$tokenType.' token');
|
||||
}
|
||||
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], $tokenType.' closer scope opener token incorrect');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], $tokenType.' closer scope closer token incorrect');
|
||||
|
||||
if (($opener + 1) !== $closer) {
|
||||
for ($i = ($opener + 1); $i < $closer; $i++) {
|
||||
$this->assertArrayHasKey(
|
||||
$token,
|
||||
$tokens[$i]['conditions'],
|
||||
$tokenType.' condition not added for token belonging to the '.$tokenType.' structure'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}//end scopeTestHelper()
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to verify that all parenthesis related array indexes for a control structure
|
||||
* token are set correctly.
|
||||
*
|
||||
* @param int $token The position of the control structure token.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function parenthesisTestHelper($token)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$tokenArray = $tokens[$token];
|
||||
$tokenType = $tokenArray['type'];
|
||||
|
||||
$this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set');
|
||||
$this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set');
|
||||
$this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set');
|
||||
$this->assertSame($token, $tokenArray['parenthesis_owner'], 'Parenthesis owner is not the '.$tokenType.' token');
|
||||
|
||||
$opener = $tokenArray['parenthesis_opener'];
|
||||
$this->assertArrayHasKey('parenthesis_owner', $tokens[$opener], 'Opening parenthesis owner is not set');
|
||||
$this->assertSame($token, $tokens[$opener]['parenthesis_owner'], 'Opening parenthesis owner is not the '.$tokenType.' token');
|
||||
|
||||
$closer = $tokenArray['parenthesis_closer'];
|
||||
$this->assertArrayHasKey('parenthesis_owner', $tokens[$closer], 'Closing parenthesis owner is not set');
|
||||
$this->assertSame($token, $tokens[$closer]['parenthesis_owner'], 'Closing parenthesis owner is not the '.$tokenType.' token');
|
||||
|
||||
}//end parenthesisTestHelper()
|
||||
|
||||
|
||||
}//end class
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Numbers with PHP 7.4 underscore separators.
|
||||
*/
|
||||
|
||||
/* testSimpleLNumber */
|
||||
$foo = 1_000_000_000;
|
||||
|
||||
/* testSimpleDNumber */
|
||||
$foo = 107_925_284.88;
|
||||
|
||||
/* testFloat */
|
||||
$foo = 6.674_083e-11;
|
||||
|
||||
/* testFloat2 */
|
||||
$foo = 6.674_083e+11;
|
||||
|
||||
/* testFloat3 */
|
||||
$foo = 1_2.3_4e1_23;
|
||||
|
||||
/* testHex */
|
||||
$foo = 0xCAFE_F00D;
|
||||
|
||||
/* testHexMultiple */
|
||||
$foo = 0x42_72_6F_77_6E;
|
||||
|
||||
/* testHexInt */
|
||||
$foo = 0x42_72_6F;
|
||||
|
||||
/* testBinary */
|
||||
$foo = 0b0101_1111;
|
||||
|
||||
/* testOctal */
|
||||
$foo = 0137_041;
|
||||
|
||||
/* testExplicitOctal */
|
||||
$foo = 0o137_041;
|
||||
|
||||
/* testExplicitOctalCapitalised */
|
||||
$foo = 0O137_041;
|
||||
|
||||
/* testIntMoreThanMax */
|
||||
$foo = 10_223_372_036_854_775_807;
|
||||
|
||||
/*
|
||||
* Invalid use of numeric separators. These should not be touched by the backfill.
|
||||
*/
|
||||
|
||||
/* testInvalid1 */
|
||||
$a = 100_; // trailing
|
||||
|
||||
/* testInvalid2 */
|
||||
$a = 1__1; // next to underscore
|
||||
|
||||
/* testInvalid3 */
|
||||
$a = 1_.0; // next to decimal point
|
||||
|
||||
/* testInvalid4 */
|
||||
$a = 1._0; // next to decimal point
|
||||
|
||||
/* testInvalid5 */
|
||||
$a = 0x_123; // next to x
|
||||
|
||||
/* testInvalid6 */
|
||||
$a = 0b_101; // next to b
|
||||
|
||||
/* testInvalid7 */
|
||||
$a = 1_e2; // next to e
|
||||
|
||||
/* testInvalid8 */
|
||||
$a = 1e_2; // next to e
|
||||
|
||||
/* testInvalid9 */
|
||||
$testValue = 107_925_284 .88;
|
||||
|
||||
/* testInvalid10 */
|
||||
$testValue = 107_925_284/*comment*/.88;
|
||||
|
||||
/* testInvalid11 */
|
||||
$foo = 0o_137;
|
||||
|
||||
/* testInvalid12 */
|
||||
$foo = 0O_41;
|
||||
|
||||
/*
|
||||
* Ensure that legitimate calculations are not touched by the backfill.
|
||||
*/
|
||||
|
||||
/* testCalc1 */
|
||||
$a = 667_083 - 11; // Calculation.
|
||||
|
||||
/* test Calc2 */
|
||||
$a = 6.674_08e3 + 11; // Calculation.
|
||||
+420
@@ -0,0 +1,420 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the backfilling of numeric separators to PHP < 7.4.
|
||||
*
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class BackfillNumericSeparatorTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that numbers using numeric separators are tokenized correctly.
|
||||
*
|
||||
* @param array $testData The data required for the specific test case.
|
||||
*
|
||||
* @dataProvider dataTestBackfill
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBackfill($testData)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$number = $this->getTargetToken($testData['marker'], [T_LNUMBER, T_DNUMBER]);
|
||||
|
||||
$this->assertSame(constant($testData['type']), $tokens[$number]['code']);
|
||||
$this->assertSame($testData['type'], $tokens[$number]['type']);
|
||||
$this->assertSame($testData['value'], $tokens[$number]['content']);
|
||||
|
||||
}//end testBackfill()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testBackfill()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataTestBackfill()
|
||||
{
|
||||
$testHexType = 'T_LNUMBER';
|
||||
if (PHP_INT_MAX < 0xCAFEF00D) {
|
||||
$testHexType = 'T_DNUMBER';
|
||||
}
|
||||
|
||||
$testHexMultipleType = 'T_LNUMBER';
|
||||
if (PHP_INT_MAX < 0x42726F776E) {
|
||||
$testHexMultipleType = 'T_DNUMBER';
|
||||
}
|
||||
|
||||
$testIntMoreThanMaxType = 'T_LNUMBER';
|
||||
if (PHP_INT_MAX < 10223372036854775807) {
|
||||
$testIntMoreThanMaxType = 'T_DNUMBER';
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
[
|
||||
'marker' => '/* testSimpleLNumber */',
|
||||
'type' => 'T_LNUMBER',
|
||||
'value' => '1_000_000_000',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testSimpleDNumber */',
|
||||
'type' => 'T_DNUMBER',
|
||||
'value' => '107_925_284.88',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testFloat */',
|
||||
'type' => 'T_DNUMBER',
|
||||
'value' => '6.674_083e-11',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testFloat2 */',
|
||||
'type' => 'T_DNUMBER',
|
||||
'value' => '6.674_083e+11',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testFloat3 */',
|
||||
'type' => 'T_DNUMBER',
|
||||
'value' => '1_2.3_4e1_23',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testHex */',
|
||||
'type' => $testHexType,
|
||||
'value' => '0xCAFE_F00D',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testHexMultiple */',
|
||||
'type' => $testHexMultipleType,
|
||||
'value' => '0x42_72_6F_77_6E',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testHexInt */',
|
||||
'type' => 'T_LNUMBER',
|
||||
'value' => '0x42_72_6F',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testBinary */',
|
||||
'type' => 'T_LNUMBER',
|
||||
'value' => '0b0101_1111',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testOctal */',
|
||||
'type' => 'T_LNUMBER',
|
||||
'value' => '0137_041',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testExplicitOctal */',
|
||||
'type' => 'T_LNUMBER',
|
||||
'value' => '0o137_041',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testExplicitOctalCapitalised */',
|
||||
'type' => 'T_LNUMBER',
|
||||
'value' => '0O137_041',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'marker' => '/* testIntMoreThanMax */',
|
||||
'type' => $testIntMoreThanMaxType,
|
||||
'value' => '10_223_372_036_854_775_807',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataTestBackfill()
|
||||
|
||||
|
||||
/**
|
||||
* Test that numbers using numeric separators which are considered parse errors and/or
|
||||
* which aren't relevant to the backfill, do not incorrectly trigger the backfill anyway.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param array $expectedTokens The token type and content of the expected token sequence.
|
||||
*
|
||||
* @dataProvider dataNoBackfill
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNoBackfill($testMarker, $expectedTokens)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$number = $this->getTargetToken($testMarker, [T_LNUMBER, T_DNUMBER]);
|
||||
|
||||
foreach ($expectedTokens as $key => $expectedToken) {
|
||||
$i = ($number + $key);
|
||||
$this->assertSame($expectedToken['code'], $tokens[$i]['code']);
|
||||
$this->assertSame($expectedToken['content'], $tokens[$i]['content']);
|
||||
}
|
||||
|
||||
}//end testNoBackfill()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testBackfill()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNoBackfill()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testInvalid1 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '100',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => '_',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid2 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '1',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => '__1',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid3 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '1',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => '_',
|
||||
],
|
||||
[
|
||||
'code' => T_DNUMBER,
|
||||
'content' => '.0',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid4 */',
|
||||
[
|
||||
[
|
||||
'code' => T_DNUMBER,
|
||||
'content' => '1.',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => '_0',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid5 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '0',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => 'x_123',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid6 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '0',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => 'b_101',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid7 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '1',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => '_e2',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid8 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '1',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => 'e_2',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid9 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '107_925_284',
|
||||
],
|
||||
[
|
||||
'code' => T_WHITESPACE,
|
||||
'content' => ' ',
|
||||
],
|
||||
[
|
||||
'code' => T_DNUMBER,
|
||||
'content' => '.88',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid10 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '107_925_284',
|
||||
],
|
||||
[
|
||||
'code' => T_COMMENT,
|
||||
'content' => '/*comment*/',
|
||||
],
|
||||
[
|
||||
'code' => T_DNUMBER,
|
||||
'content' => '.88',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid11 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '0',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => 'o_137',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInvalid12 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '0',
|
||||
],
|
||||
[
|
||||
'code' => T_STRING,
|
||||
'content' => 'O_41',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testCalc1 */',
|
||||
[
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '667_083',
|
||||
],
|
||||
[
|
||||
'code' => T_WHITESPACE,
|
||||
'content' => ' ',
|
||||
],
|
||||
[
|
||||
'code' => T_MINUS,
|
||||
'content' => '-',
|
||||
],
|
||||
[
|
||||
'code' => T_WHITESPACE,
|
||||
'content' => ' ',
|
||||
],
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '11',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* test Calc2 */',
|
||||
[
|
||||
[
|
||||
'code' => T_DNUMBER,
|
||||
'content' => '6.674_08e3',
|
||||
],
|
||||
[
|
||||
'code' => T_WHITESPACE,
|
||||
'content' => ' ',
|
||||
],
|
||||
[
|
||||
'code' => T_PLUS,
|
||||
'content' => '+',
|
||||
],
|
||||
[
|
||||
'code' => T_WHITESPACE,
|
||||
'content' => ' ',
|
||||
],
|
||||
[
|
||||
'code' => T_LNUMBER,
|
||||
'content' => '11',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataNoBackfill()
|
||||
|
||||
|
||||
}//end class
|
||||
lib/zxcvbn-php-master/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc
Vendored
+100
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
class Foo
|
||||
{
|
||||
/* testReadonlyProperty */
|
||||
readonly int $readonlyProperty;
|
||||
/* testVarReadonlyProperty */
|
||||
var readonly int $varReadonlyProperty;
|
||||
/* testReadonlyVarProperty */
|
||||
readonly var int $testReadonlyVarProperty;
|
||||
/* testStaticReadonlyProperty */
|
||||
static readonly int $staticReadonlyProperty;
|
||||
/* testReadonlyStaticProperty */
|
||||
readonly static int $readonlyStaticProperty;
|
||||
/* testConstReadonlyProperty */
|
||||
public readonly const MYCONSTANT = 'foo';
|
||||
/* testReadonlyPropertyWithoutType */
|
||||
readonly $propertyWithoutType;
|
||||
/* testPublicReadonlyProperty */
|
||||
public readonly int $publicReadonlyProperty;
|
||||
/* testProtectedReadonlyProperty */
|
||||
protected readonly int $protectedReadonlyProperty;
|
||||
/* testPrivateReadonlyProperty */
|
||||
private readonly int $privateReadonlyProperty;
|
||||
/* testPublicReadonlyPropertyWithReadonlyFirst */
|
||||
readonly public int $publicReadonlyProperty;
|
||||
/* testProtectedReadonlyPropertyWithReadonlyFirst */
|
||||
readonly protected int $protectedReadonlyProperty;
|
||||
/* testPrivateReadonlyPropertyWithReadonlyFirst */
|
||||
readonly private int $privateReadonlyProperty;
|
||||
/* testReadonlyWithCommentsInDeclaration */
|
||||
private /* Comment */ readonly /* Comment */ int /* Comment */ $readonlyPropertyWithCommentsInDeclaration;
|
||||
/* testReadonlyWithNullableProperty */
|
||||
private readonly ?int $nullableProperty;
|
||||
/* testReadonlyNullablePropertyWithUnionTypeHintAndNullFirst */
|
||||
private readonly null|int $nullablePropertyWithUnionTypeHintAndNullFirst;
|
||||
/* testReadonlyNullablePropertyWithUnionTypeHintAndNullLast */
|
||||
private readonly int|null $nullablePropertyWithUnionTypeHintAndNullLast;
|
||||
/* testReadonlyPropertyWithArrayTypeHint */
|
||||
private readonly array $arrayProperty;
|
||||
/* testReadonlyPropertyWithSelfTypeHint */
|
||||
private readonly self $selfProperty;
|
||||
/* testReadonlyPropertyWithParentTypeHint */
|
||||
private readonly parent $parentProperty;
|
||||
/* testReadonlyPropertyWithFullyQualifiedTypeHint */
|
||||
private readonly \stdClass $propertyWithFullyQualifiedTypeHint;
|
||||
|
||||
/* testReadonlyIsCaseInsensitive */
|
||||
public ReAdOnLy string $caseInsensitiveProperty;
|
||||
|
||||
/* testReadonlyConstructorPropertyPromotion */
|
||||
public function __construct(private readonly bool $constructorPropertyPromotion)
|
||||
{
|
||||
}
|
||||
|
||||
/* testReadonlyConstructorPropertyPromotionWithReference */
|
||||
public function __construct(private ReadOnly bool &$constructorPropertyPromotion) {}
|
||||
}
|
||||
|
||||
$anonymousClass = new class () {
|
||||
/* testReadonlyPropertyInAnonymousClass */
|
||||
public readonly int $property;
|
||||
};
|
||||
|
||||
class ClassName {
|
||||
/* testReadonlyUsedAsClassConstantName */
|
||||
const READONLY = 'readonly';
|
||||
|
||||
/* testReadonlyUsedAsMethodName */
|
||||
public function readonly() {
|
||||
// Do something.
|
||||
|
||||
/* testReadonlyUsedAsPropertyName */
|
||||
$this->readonly = 'foo';
|
||||
|
||||
/* testReadonlyPropertyInTernaryOperator */
|
||||
$isReadonly = $this->readonly ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
/* testReadonlyUsedAsFunctionName */
|
||||
function readonly()
|
||||
{
|
||||
}
|
||||
|
||||
/* testReadonlyUsedAsNamespaceName */
|
||||
namespace Readonly;
|
||||
/* testReadonlyUsedAsPartOfNamespaceName */
|
||||
namespace My\Readonly\Collection;
|
||||
/* testReadonlyAsFunctionCall */
|
||||
$var = readonly($a, $b);
|
||||
/* testClassConstantFetchWithReadonlyAsConstantName */
|
||||
echo ClassName::READONLY;
|
||||
|
||||
/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */
|
||||
$var = readonly /* comment */ ();
|
||||
|
||||
/* testParseErrorLiveCoding */
|
||||
// This must be the last test in the file.
|
||||
readonly
|
||||
lib/zxcvbn-php-master/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php
Vendored
+236
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the support of PHP 8.1 "readonly" keyword.
|
||||
*
|
||||
* @author Jaroslav Hanslík <kukulich@kukulich.cz>
|
||||
* @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class BackfillReadonlyTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that the "readonly" keyword is tokenized as such.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataReadonly
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReadonly($testMarker, $testContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent);
|
||||
$this->assertSame(T_READONLY, $tokens[$target]['code']);
|
||||
$this->assertSame('T_READONLY', $tokens[$target]['type']);
|
||||
|
||||
}//end testReadonly()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testReadonly()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataReadonly()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testReadonlyProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testVarReadonlyProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyVarProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testStaticReadonlyProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyStaticProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testConstReadonlyProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyPropertyWithoutType */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testPublicReadonlyProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testProtectedReadonlyProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testPrivateReadonlyProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testPublicReadonlyPropertyWithReadonlyFirst */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testProtectedReadonlyPropertyWithReadonlyFirst */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testPrivateReadonlyPropertyWithReadonlyFirst */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyWithCommentsInDeclaration */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyWithNullableProperty */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyNullablePropertyWithUnionTypeHintAndNullFirst */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyNullablePropertyWithUnionTypeHintAndNullLast */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyPropertyWithArrayTypeHint */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyPropertyWithSelfTypeHint */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyPropertyWithParentTypeHint */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyPropertyWithFullyQualifiedTypeHint */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyIsCaseInsensitive */',
|
||||
'ReAdOnLy',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyConstructorPropertyPromotion */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyConstructorPropertyPromotionWithReference */',
|
||||
'ReadOnly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyPropertyInAnonymousClass */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testParseErrorLiveCoding */',
|
||||
'readonly',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataReadonly()
|
||||
|
||||
|
||||
/**
|
||||
* Test that "readonly" when not used as the keyword is still tokenized as `T_STRING`.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataNotReadonly
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotReadonly($testMarker, $testContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent);
|
||||
$this->assertSame(T_STRING, $tokens[$target]['code']);
|
||||
$this->assertSame('T_STRING', $tokens[$target]['type']);
|
||||
|
||||
}//end testNotReadonly()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNotReadonly()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNotReadonly()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testReadonlyUsedAsClassConstantName */',
|
||||
'READONLY',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyUsedAsMethodName */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyUsedAsPropertyName */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyPropertyInTernaryOperator */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyUsedAsFunctionName */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyUsedAsNamespaceName */',
|
||||
'Readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyUsedAsPartOfNamespaceName */',
|
||||
'Readonly',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyAsFunctionCall */',
|
||||
'readonly',
|
||||
],
|
||||
[
|
||||
'/* testClassConstantFetchWithReadonlyAsConstantName */',
|
||||
'READONLY',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataNotReadonly()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+134
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Type union or bitwise or.
|
||||
*/
|
||||
|
||||
/* testBitwiseOr1 */
|
||||
$result = $value | $test /* testBitwiseOr2 */ | $another;
|
||||
|
||||
class TypeUnion
|
||||
{
|
||||
/* testTypeUnionPropertySimple */
|
||||
public static Foo|Bar $obj;
|
||||
|
||||
/* testTypeUnionPropertyReverseModifierOrder */
|
||||
static protected int|float $number /* testBitwiseOrPropertyDefaultValue */ = E_WARNING | E_NOTICE;
|
||||
|
||||
private
|
||||
/* testTypeUnionPropertyMulti1 */
|
||||
array |
|
||||
/* testTypeUnionPropertyMulti2 */
|
||||
Traversable | // phpcs:ignore Stnd.Cat.Sniff
|
||||
false
|
||||
/* testTypeUnionPropertyMulti3 */
|
||||
| null $arrayOrFalse;
|
||||
|
||||
/* testTypeUnionPropertyNamespaceRelative */
|
||||
public namespace\Sub\NameA|namespace\Sub\NameB $namespaceRelative;
|
||||
|
||||
/* testTypeUnionPropertyPartiallyQualified */
|
||||
public Partially\Qualified\NameA|Partially\Qualified\NameB $partiallyQual;
|
||||
|
||||
/* testTypeUnionPropertyFullyQualified */
|
||||
public \Fully\Qualified\NameA|\Fully\Qualified\NameB $fullyQual;
|
||||
|
||||
/* testTypeUnionPropertyWithReadOnlyKeyword */
|
||||
protected readonly string|null $array;
|
||||
|
||||
/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */
|
||||
static readonly string|null $array;
|
||||
|
||||
/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */
|
||||
var readonly string|null $array;
|
||||
|
||||
/* testTypeUnionPropertyWithReadOnlyKeywordFirst */
|
||||
readonly protected string|null $array;
|
||||
|
||||
/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */
|
||||
readonly string|null $nullableString;
|
||||
|
||||
public function paramTypes(
|
||||
/* testTypeUnionParam1 */
|
||||
int|float $paramA /* testBitwiseOrParamDefaultValue */ = CONSTANT_A | CONSTANT_B,
|
||||
|
||||
/* testTypeUnionParam2 */
|
||||
Foo|\Bar /* testTypeUnionParam3 */ |Baz &...$paramB = null,
|
||||
) {
|
||||
/* testBitwiseOr3 */
|
||||
return (($a1 ^ $b1) |($a2 ^ $b2)) + $c;
|
||||
}
|
||||
|
||||
public function identifierNames(
|
||||
/* testTypeUnionParamNamespaceRelative */
|
||||
namespace\Sub\NameA|namespace\Sub\NameB $paramA,
|
||||
/* testTypeUnionParamPartiallyQualified */
|
||||
Partially\Qualified\NameA|Partially\Qualified\NameB $paramB,
|
||||
/* testTypeUnionParamFullyQualified */
|
||||
\Fully\Qualified\NameA|\Fully\Qualified\NameB $paramC,
|
||||
) {}
|
||||
|
||||
/* testTypeUnionReturnType */
|
||||
public function returnType() : int|false {}
|
||||
|
||||
/* testTypeUnionConstructorPropertyPromotion */
|
||||
public function __construct( public bool|null $property) {}
|
||||
|
||||
/* testTypeUnionAbstractMethodReturnType1 */
|
||||
abstract public function abstractMethod(): object|array /* testTypeUnionAbstractMethodReturnType2 */ |false;
|
||||
|
||||
/* testTypeUnionReturnTypeNamespaceRelative */
|
||||
public function identifierNamesReturnRelative() : namespace\Sub\NameA|namespace\Sub\NameB {}
|
||||
|
||||
/* testTypeUnionReturnPartiallyQualified */
|
||||
public function identifierNamesReturnPQ() : Partially\Qualified\NameA|Partially\Qualified\NameB {}
|
||||
|
||||
/* testTypeUnionReturnFullyQualified */
|
||||
public function identifierNamesReturnFQ() : \Fully\Qualified\NameA|\Fully\Qualified\NameB {}
|
||||
}
|
||||
|
||||
/* testTypeUnionClosureParamIllegalNullable */
|
||||
$closureWithParamType = function (?string|null $string) {};
|
||||
|
||||
function globalFunctionWithSpreadAndReference(
|
||||
/* testTypeUnionWithReference */
|
||||
float|null &$paramA,
|
||||
/* testTypeUnionWithSpreadOperator */
|
||||
string|int ...$paramB
|
||||
) {}
|
||||
|
||||
/* testBitwiseOrClosureParamDefault */
|
||||
$closureWithReturnType = function ($string = NONSENSE | FAKE)/* testTypeUnionClosureReturn */ : \Package\MyA|PackageB {};
|
||||
|
||||
/* testTypeUnionArrowParam */
|
||||
$arrowWithParamType = fn (object|array $param, /* testBitwiseOrArrowParamDefault */ ?int $int = CONSTA | CONSTB )
|
||||
/* testBitwiseOrArrowExpression */
|
||||
=> $param | $int;
|
||||
|
||||
/* testTypeUnionArrowReturnType */
|
||||
$arrowWithReturnType = fn ($param) : int|null => $param * 10;
|
||||
|
||||
/* testBitwiseOrInArrayKey */
|
||||
$array = array(
|
||||
A | B => /* testBitwiseOrInArrayValue */ B | C
|
||||
);
|
||||
|
||||
/* testBitwiseOrInShortArrayKey */
|
||||
$array = [
|
||||
A | B => /* testBitwiseOrInShortArrayValue */ B | C
|
||||
];
|
||||
|
||||
/* testBitwiseOrTryCatch */
|
||||
try {
|
||||
} catch ( ExceptionA | ExceptionB $e ) {
|
||||
}
|
||||
|
||||
/* testBitwiseOrNonArrowFnFunctionCall */
|
||||
$obj->fn($something | $else);
|
||||
|
||||
/* testTypeUnionNonArrowFunctionDeclaration */
|
||||
function &fn(int|false $something) {}
|
||||
|
||||
/* testLiveCoding */
|
||||
// Intentional parse error. This has to be the last test in the file.
|
||||
return function( type|
|
||||
Vendored
+138
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the conversion of bitwise or tokens to type union tokens.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class BitwiseOrTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that non-union type bitwise or tokens are still tokenized as bitwise or.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataBitwiseOr
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBitwiseOr($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$opener = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]);
|
||||
$this->assertSame(T_BITWISE_OR, $tokens[$opener]['code']);
|
||||
$this->assertSame('T_BITWISE_OR', $tokens[$opener]['type']);
|
||||
|
||||
}//end testBitwiseOr()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testBitwiseOr()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataBitwiseOr()
|
||||
{
|
||||
return [
|
||||
['/* testBitwiseOr1 */'],
|
||||
['/* testBitwiseOr2 */'],
|
||||
['/* testBitwiseOrPropertyDefaultValue */'],
|
||||
['/* testBitwiseOrParamDefaultValue */'],
|
||||
['/* testBitwiseOr3 */'],
|
||||
['/* testBitwiseOrClosureParamDefault */'],
|
||||
['/* testBitwiseOrArrowParamDefault */'],
|
||||
['/* testBitwiseOrArrowExpression */'],
|
||||
['/* testBitwiseOrInArrayKey */'],
|
||||
['/* testBitwiseOrInArrayValue */'],
|
||||
['/* testBitwiseOrInShortArrayKey */'],
|
||||
['/* testBitwiseOrInShortArrayValue */'],
|
||||
['/* testBitwiseOrTryCatch */'],
|
||||
['/* testBitwiseOrNonArrowFnFunctionCall */'],
|
||||
['/* testLiveCoding */'],
|
||||
];
|
||||
|
||||
}//end dataBitwiseOr()
|
||||
|
||||
|
||||
/**
|
||||
* Test that bitwise or tokens when used as part of a union type are tokenized as `T_TYPE_UNION`.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataTypeUnion
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTypeUnion($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$opener = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]);
|
||||
$this->assertSame(T_TYPE_UNION, $tokens[$opener]['code']);
|
||||
$this->assertSame('T_TYPE_UNION', $tokens[$opener]['type']);
|
||||
|
||||
}//end testTypeUnion()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testTypeUnion()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataTypeUnion()
|
||||
{
|
||||
return [
|
||||
['/* testTypeUnionPropertySimple */'],
|
||||
['/* testTypeUnionPropertyReverseModifierOrder */'],
|
||||
['/* testTypeUnionPropertyMulti1 */'],
|
||||
['/* testTypeUnionPropertyMulti2 */'],
|
||||
['/* testTypeUnionPropertyMulti3 */'],
|
||||
['/* testTypeUnionPropertyNamespaceRelative */'],
|
||||
['/* testTypeUnionPropertyPartiallyQualified */'],
|
||||
['/* testTypeUnionPropertyFullyQualified */'],
|
||||
['/* testTypeUnionPropertyWithReadOnlyKeyword */'],
|
||||
['/* testTypeUnionPropertyWithReadOnlyKeywordFirst */'],
|
||||
['/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */'],
|
||||
['/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */'],
|
||||
['/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */'],
|
||||
['/* testTypeUnionParam1 */'],
|
||||
['/* testTypeUnionParam2 */'],
|
||||
['/* testTypeUnionParam3 */'],
|
||||
['/* testTypeUnionParamNamespaceRelative */'],
|
||||
['/* testTypeUnionParamPartiallyQualified */'],
|
||||
['/* testTypeUnionParamFullyQualified */'],
|
||||
['/* testTypeUnionReturnType */'],
|
||||
['/* testTypeUnionConstructorPropertyPromotion */'],
|
||||
['/* testTypeUnionAbstractMethodReturnType1 */'],
|
||||
['/* testTypeUnionAbstractMethodReturnType2 */'],
|
||||
['/* testTypeUnionReturnTypeNamespaceRelative */'],
|
||||
['/* testTypeUnionReturnPartiallyQualified */'],
|
||||
['/* testTypeUnionReturnFullyQualified */'],
|
||||
['/* testTypeUnionClosureParamIllegalNullable */'],
|
||||
['/* testTypeUnionWithReference */'],
|
||||
['/* testTypeUnionWithSpreadOperator */'],
|
||||
['/* testTypeUnionClosureReturn */'],
|
||||
['/* testTypeUnionArrowParam */'],
|
||||
['/* testTypeUnionArrowReturnType */'],
|
||||
['/* testTypeUnionNonArrowFunctionDeclaration */'],
|
||||
];
|
||||
|
||||
}//end dataTypeUnion()
|
||||
|
||||
|
||||
}//end class
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
|
||||
/* testNamespaceIsKeyword */
|
||||
namespace SomeNamespace;
|
||||
|
||||
class ContextSensitiveKeywords
|
||||
{
|
||||
const /* testAbstract */ ABSTRACT = 'ABSTRACT';
|
||||
const /* testArray */ ARRAY = 'ARRAY';
|
||||
const /* testAs */ AS = 'AS';
|
||||
const /* testBreak */ BREAK = 'BREAK';
|
||||
const /* testCallable */ CALLABLE = 'CALLABLE';
|
||||
const /* testCase */ CASE = 'CASE';
|
||||
const /* testCatch */ CATCH = 'CATCH';
|
||||
const /* testClass */ CLASS = 'CLASS';
|
||||
const /* testClone */ CLONE = 'CLONE';
|
||||
const /* testConst */ CONST = 'CONST';
|
||||
const /* testContinue */ CONTINUE = 'CONTINUE';
|
||||
const /* testDeclare */ DECLARE = 'DECLARE';
|
||||
const /* testDefault */ DEFAULT = 'DEFAULT';
|
||||
const /* testDo */ DO = 'DO';
|
||||
const /* testEcho */ ECHO = 'ECHO';
|
||||
const /* testElse */ ELSE = 'ELSE';
|
||||
const /* testElseIf */ ELSEIF = 'ELSEIF';
|
||||
const /* testEmpty */ EMPTY = 'EMPTY';
|
||||
const /* testEndDeclare */ ENDDECLARE = 'ENDDECLARE';
|
||||
const /* testEndFor */ ENDFOR = 'ENDFOR';
|
||||
const /* testEndForeach */ ENDFOREACH = 'ENDFOREACH';
|
||||
const /* testEndIf */ ENDIF = 'ENDIF';
|
||||
const /* testEndSwitch */ ENDSWITCH = 'ENDSWITCH';
|
||||
const /* testEndWhile */ ENDWHILE = 'ENDWHILE';
|
||||
const /* testEnum */ ENUM = 'ENUM';
|
||||
const /* testEval */ EVAL = 'EVAL';
|
||||
const /* testExit */ EXIT = 'EXIT';
|
||||
const /* testExtends */ EXTENDS = 'EXTENDS';
|
||||
const /* testFinal */ FINAL = 'FINAL';
|
||||
const /* testFinally */ FINALLY = 'FINALLY';
|
||||
const /* testFn */ FN = 'FN';
|
||||
const /* testFor */ FOR = 'FOR';
|
||||
const /* testForeach */ FOREACH = 'FOREACH';
|
||||
const /* testFunction */ FUNCTION = 'FUNCTION';
|
||||
const /* testGlobal */ GLOBAL = 'GLOBAL';
|
||||
const /* testGoto */ GOTO = 'GOTO';
|
||||
const /* testIf */ IF = 'IF';
|
||||
const /* testImplements */ IMPLEMENTS = 'IMPLEMENTS';
|
||||
const /* testInclude */ INCLUDE = 'INCLUDE';
|
||||
const /* testIncludeOnce */ INCLUDE_ONCE = 'INCLUDE_ONCE';
|
||||
const /* testInstanceOf */ INSTANCEOF = 'INSTANCEOF';
|
||||
const /* testInsteadOf */ INSTEADOF = 'INSTEADOF';
|
||||
const /* testInterface */ INTERFACE = 'INTERFACE';
|
||||
const /* testIsset */ ISSET = 'ISSET';
|
||||
const /* testList */ LIST = 'LIST';
|
||||
const /* testMatch */ MATCH = 'MATCH';
|
||||
const /* testNamespace */ NAMESPACE = 'NAMESPACE';
|
||||
const /* testNew */ NEW = 'NEW';
|
||||
const /* testParent */ PARENT = 'PARENT';
|
||||
const /* testPrint */ PRINT = 'PRINT';
|
||||
const /* testPrivate */ PRIVATE = 'PRIVATE';
|
||||
const /* testProtected */ PROTECTED = 'PROTECTED';
|
||||
const /* testPublic */ PUBLIC = 'PUBLIC';
|
||||
const /* testReadonly */ READONLY = 'READONLY';
|
||||
const /* testRequire */ REQUIRE = 'REQUIRE';
|
||||
const /* testRequireOnce */ REQUIRE_ONCE = 'REQUIRE_ONCE';
|
||||
const /* testReturn */ RETURN = 'RETURN';
|
||||
const /* testSelf */ SELF = 'SELF';
|
||||
const /* testStatic */ STATIC = 'STATIC';
|
||||
const /* testSwitch */ SWITCH = 'SWITCH';
|
||||
const /* testThrows */ THROW = 'THROW';
|
||||
const /* testTrait */ TRAIT = 'TRAIT';
|
||||
const /* testTry */ TRY = 'TRY';
|
||||
const /* testUnset */ UNSET = 'UNSET';
|
||||
const /* testUse */ USE = 'USE';
|
||||
const /* testVar */ VAR = 'VAR';
|
||||
const /* testWhile */ WHILE = 'WHILE';
|
||||
const /* testYield */ YIELD = 'YIELD';
|
||||
const /* testYieldFrom */ YIELD_FROM = 'YIELD_FROM';
|
||||
|
||||
const /* testAnd */ AND = 'LOGICAL_AND';
|
||||
const /* testOr */ OR = 'LOGICAL_OR';
|
||||
const /* testXor */ XOR = 'LOGICAL_XOR';
|
||||
}
|
||||
|
||||
namespace /* testKeywordAfterNamespaceShouldBeString */ class;
|
||||
namespace /* testNamespaceNameIsString1 */ my\ /* testNamespaceNameIsString2 */ class\ /* testNamespaceNameIsString3 */ foreach;
|
||||
|
||||
/* testAbstractIsKeyword */ abstract /* testClassIsKeyword */ class SomeClass
|
||||
/* testExtendsIsKeyword */ extends SomeParent
|
||||
/* testImplementsIsKeyword */ implements SomeInterface
|
||||
{
|
||||
/* testUseIsKeyword */ use SomeTrait, OtherTrait {
|
||||
SomeTrait::a /* testInsteadOfIsKeyword */ insteadof A;
|
||||
OtherTrait::a /* testAsIsKeyword */ as B;
|
||||
}
|
||||
|
||||
/* testConstIsKeyword */ const CONSTANT = 'c';
|
||||
|
||||
/* testPrivateIsKeyword */ private $private;
|
||||
/* testProtectedIsKeyword */ protected $protected;
|
||||
/* testPublicIsKeyword */ public $public;
|
||||
|
||||
/* testVarIsKeyword */ var $var;
|
||||
/* testStaticIsKeyword */ static $static;
|
||||
|
||||
/* testReadonlyIsKeyword */ readonly $readonly;
|
||||
|
||||
/* testFinalIsKeyword */ final /* testFunctionIsKeyword */ function someFunction(
|
||||
/* testCallableIsKeyword */
|
||||
callable $callable,
|
||||
/* testSelfIsKeyword */
|
||||
self $self,
|
||||
/* testParentIsKeyword */
|
||||
parent $parent
|
||||
) {
|
||||
/* testReturnIsKeyword */
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
/* testInterfaceIsKeyword */ interface SomeInterface {}
|
||||
/* testTraitIsKeyword */ trait SomeTrait {}
|
||||
/* testEnumIsKeyword */ enum SomeEnum {}
|
||||
|
||||
$object = /* testNewIsKeyword */ new SomeClass();
|
||||
$object /* testInstanceOfIsKeyword */ instanceof SomeClass;
|
||||
$copy = /* testCloneIsKeyword */ clone $object;
|
||||
|
||||
/* testIfIsKeyword */ if (/* testEmptyIsKeyword */ empty($a)):
|
||||
/* testElseIfIsKeyword */ elseif (false):
|
||||
/* testElseIsKeyword */ else:
|
||||
/* testEndIfIsKeyword */ endif;
|
||||
|
||||
/* testForIsKeyword */ for ($i = 0; $i < 100; $i++):
|
||||
/* testEndForIsKeyword */ endfor;
|
||||
|
||||
/* testForeachIsKeyword */ foreach ($array as $value):
|
||||
/* testEndForeachIsKeyword */ endforeach;
|
||||
|
||||
/* testSwitchIsKeyword */ switch (true):
|
||||
/* testCaseIsKeyword */case false:
|
||||
/* testBreakIsKeyword */
|
||||
break;
|
||||
/* testDefaultIsKeyword */ default:
|
||||
/* testContinueIsKeyword */
|
||||
continue;
|
||||
/* testEndSwitchIsKeyword */ endswitch;
|
||||
|
||||
/* testDoIsKeyword */ do {
|
||||
|
||||
} while (false);
|
||||
|
||||
/* testWhileIsKeyword */ while (false):
|
||||
/* testEndWhileIsKeyword */ endwhile;
|
||||
|
||||
/* testTryIsKeyword */
|
||||
try {
|
||||
/* testThrowIsKeyword */
|
||||
throw new Exception();
|
||||
} /* testCatchIsKeyword */ catch (Exception $e) {
|
||||
|
||||
} /* testFinallyIsKeyword */ finally {
|
||||
|
||||
}
|
||||
|
||||
/* testGlobalIsKeyword */
|
||||
global $foo;
|
||||
/* testEchoIsKeyword */
|
||||
echo $foo;
|
||||
/* testPrintIsKeyword */
|
||||
print $foo;
|
||||
/* testDieIsKeyword */
|
||||
die($foo);
|
||||
/* testEvalIsKeyword */
|
||||
eval('<?php echo 5;');
|
||||
/* testExitIsKeyword */
|
||||
exit;
|
||||
/* testIssetIsKeyword */
|
||||
$a = isset($a);
|
||||
/* testUnsetIsKeyword */
|
||||
unset($a);
|
||||
|
||||
/* testIncludeIsKeyword */
|
||||
include 'file.php';
|
||||
/* testIncludeOnceIsKeyword */
|
||||
include_once 'file.php';
|
||||
/* testRequireIsKeyword */
|
||||
require 'file.php';
|
||||
/* testRequireOnceIsKeyword */
|
||||
require_once 'file.php';
|
||||
|
||||
[$a, $b] = /* testListIsKeyword */ list($array);
|
||||
|
||||
/* testGotoIsKeyword */
|
||||
goto label;
|
||||
|
||||
$match = /* testMatchIsKeyword */ match ($test) {
|
||||
1 => 'a',
|
||||
2 => 'b',
|
||||
/* testMatchDefaultIsKeyword */ default => 'default',
|
||||
};
|
||||
|
||||
$closure = /* testFnIsKeyword */ fn () => 'string';
|
||||
|
||||
function () {
|
||||
/* testYieldIsKeyword */ yield $f;
|
||||
/* testYieldFromIsKeyword */ yield from someFunction();
|
||||
};
|
||||
|
||||
/* testDeclareIsKeyword */ declare(ticks=1):
|
||||
/* testEndDeclareIsKeyword */ enddeclare;
|
||||
|
||||
if (true /* testAndIsKeyword */ and false /* testOrIsKeyword */ or null /* testXorIsKeyword */ xor 0) {
|
||||
|
||||
}
|
||||
|
||||
$anonymousClass = new /* testAnonymousClassIsKeyword */ class {};
|
||||
$anonymousClass2 = new class /* testExtendsInAnonymousClassIsKeyword */ extends SomeParent {};
|
||||
$anonymousClass3 = new class /* testImplementsInAnonymousClassIsKeyword */ implements SomeInterface {};
|
||||
|
||||
$instantiated1 = new /* testClassInstantiationParentIsKeyword */ parent();
|
||||
$instantiated2 = new /* testClassInstantiationSelfIsKeyword */ SELF;
|
||||
$instantiated3 = new /* testClassInstantiationStaticIsKeyword */ static($param);
|
||||
|
||||
class Foo extends /* testNamespaceInNameIsKeyword */ namespace\Exception
|
||||
{}
|
||||
|
||||
function /* testKeywordAfterFunctionShouldBeString */ eval() {}
|
||||
function /* testKeywordAfterFunctionByRefShouldBeString */ &switch() {}
|
||||
+509
@@ -0,0 +1,509 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the conversion of context sensitive keywords to T_STRING.
|
||||
*
|
||||
* @author Jaroslav Hanslík <kukulich@kukulich.cz>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
|
||||
class ContextSensitiveKeywordsTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that context sensitive keyword is tokenized as string when it should be string.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataStrings
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStrings($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_STRING]));
|
||||
|
||||
$this->assertSame(T_STRING, $tokens[$token]['code']);
|
||||
$this->assertSame('T_STRING', $tokens[$token]['type']);
|
||||
|
||||
}//end testStrings()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testStrings()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataStrings()
|
||||
{
|
||||
return [
|
||||
['/* testAbstract */'],
|
||||
['/* testArray */'],
|
||||
['/* testAs */'],
|
||||
['/* testBreak */'],
|
||||
['/* testCallable */'],
|
||||
['/* testCase */'],
|
||||
['/* testCatch */'],
|
||||
['/* testClass */'],
|
||||
['/* testClone */'],
|
||||
['/* testConst */'],
|
||||
['/* testContinue */'],
|
||||
['/* testDeclare */'],
|
||||
['/* testDefault */'],
|
||||
['/* testDo */'],
|
||||
['/* testEcho */'],
|
||||
['/* testElse */'],
|
||||
['/* testElseIf */'],
|
||||
['/* testEmpty */'],
|
||||
['/* testEndDeclare */'],
|
||||
['/* testEndFor */'],
|
||||
['/* testEndForeach */'],
|
||||
['/* testEndIf */'],
|
||||
['/* testEndSwitch */'],
|
||||
['/* testEndWhile */'],
|
||||
['/* testEnum */'],
|
||||
['/* testEval */'],
|
||||
['/* testExit */'],
|
||||
['/* testExtends */'],
|
||||
['/* testFinal */'],
|
||||
['/* testFinally */'],
|
||||
['/* testFn */'],
|
||||
['/* testFor */'],
|
||||
['/* testForeach */'],
|
||||
['/* testFunction */'],
|
||||
['/* testGlobal */'],
|
||||
['/* testGoto */'],
|
||||
['/* testIf */'],
|
||||
['/* testImplements */'],
|
||||
['/* testInclude */'],
|
||||
['/* testIncludeOnce */'],
|
||||
['/* testInstanceOf */'],
|
||||
['/* testInsteadOf */'],
|
||||
['/* testInterface */'],
|
||||
['/* testIsset */'],
|
||||
['/* testList */'],
|
||||
['/* testMatch */'],
|
||||
['/* testNamespace */'],
|
||||
['/* testNew */'],
|
||||
['/* testParent */'],
|
||||
['/* testPrint */'],
|
||||
['/* testPrivate */'],
|
||||
['/* testProtected */'],
|
||||
['/* testPublic */'],
|
||||
['/* testReadonly */'],
|
||||
['/* testRequire */'],
|
||||
['/* testRequireOnce */'],
|
||||
['/* testReturn */'],
|
||||
['/* testSelf */'],
|
||||
['/* testStatic */'],
|
||||
['/* testSwitch */'],
|
||||
['/* testThrows */'],
|
||||
['/* testTrait */'],
|
||||
['/* testTry */'],
|
||||
['/* testUnset */'],
|
||||
['/* testUse */'],
|
||||
['/* testVar */'],
|
||||
['/* testWhile */'],
|
||||
['/* testYield */'],
|
||||
['/* testYieldFrom */'],
|
||||
['/* testAnd */'],
|
||||
['/* testOr */'],
|
||||
['/* testXor */'],
|
||||
|
||||
['/* testKeywordAfterNamespaceShouldBeString */'],
|
||||
['/* testNamespaceNameIsString1 */'],
|
||||
['/* testNamespaceNameIsString2 */'],
|
||||
['/* testNamespaceNameIsString3 */'],
|
||||
|
||||
['/* testKeywordAfterFunctionShouldBeString */'],
|
||||
['/* testKeywordAfterFunctionByRefShouldBeString */'],
|
||||
];
|
||||
|
||||
}//end dataStrings()
|
||||
|
||||
|
||||
/**
|
||||
* Test that context sensitive keyword is tokenized as keyword when it should be keyword.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param string $expectedTokenType The expected token type.
|
||||
*
|
||||
* @dataProvider dataKeywords
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testKeywords($testMarker, $expectedTokenType)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_ANON_CLASS, T_MATCH_DEFAULT, T_PARENT, T_SELF, T_STRING]));
|
||||
|
||||
$this->assertSame(constant($expectedTokenType), $tokens[$token]['code']);
|
||||
$this->assertSame($expectedTokenType, $tokens[$token]['type']);
|
||||
|
||||
}//end testKeywords()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testKeywords()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataKeywords()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testNamespaceIsKeyword */',
|
||||
'T_NAMESPACE',
|
||||
],
|
||||
[
|
||||
'/* testAbstractIsKeyword */',
|
||||
'T_ABSTRACT',
|
||||
],
|
||||
[
|
||||
'/* testClassIsKeyword */',
|
||||
'T_CLASS',
|
||||
],
|
||||
[
|
||||
'/* testExtendsIsKeyword */',
|
||||
'T_EXTENDS',
|
||||
],
|
||||
[
|
||||
'/* testImplementsIsKeyword */',
|
||||
'T_IMPLEMENTS',
|
||||
],
|
||||
[
|
||||
'/* testUseIsKeyword */',
|
||||
'T_USE',
|
||||
],
|
||||
[
|
||||
'/* testInsteadOfIsKeyword */',
|
||||
'T_INSTEADOF',
|
||||
],
|
||||
[
|
||||
'/* testAsIsKeyword */',
|
||||
'T_AS',
|
||||
],
|
||||
[
|
||||
'/* testConstIsKeyword */',
|
||||
'T_CONST',
|
||||
],
|
||||
[
|
||||
'/* testPrivateIsKeyword */',
|
||||
'T_PRIVATE',
|
||||
],
|
||||
[
|
||||
'/* testProtectedIsKeyword */',
|
||||
'T_PROTECTED',
|
||||
],
|
||||
[
|
||||
'/* testPublicIsKeyword */',
|
||||
'T_PUBLIC',
|
||||
],
|
||||
[
|
||||
'/* testVarIsKeyword */',
|
||||
'T_VAR',
|
||||
],
|
||||
[
|
||||
'/* testStaticIsKeyword */',
|
||||
'T_STATIC',
|
||||
],
|
||||
[
|
||||
'/* testReadonlyIsKeyword */',
|
||||
'T_READONLY',
|
||||
],
|
||||
[
|
||||
'/* testFinalIsKeyword */',
|
||||
'T_FINAL',
|
||||
],
|
||||
[
|
||||
'/* testFunctionIsKeyword */',
|
||||
'T_FUNCTION',
|
||||
],
|
||||
[
|
||||
'/* testCallableIsKeyword */',
|
||||
'T_CALLABLE',
|
||||
],
|
||||
[
|
||||
'/* testSelfIsKeyword */',
|
||||
'T_SELF',
|
||||
],
|
||||
[
|
||||
'/* testParentIsKeyword */',
|
||||
'T_PARENT',
|
||||
],
|
||||
[
|
||||
'/* testReturnIsKeyword */',
|
||||
'T_RETURN',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testInterfaceIsKeyword */',
|
||||
'T_INTERFACE',
|
||||
],
|
||||
[
|
||||
'/* testTraitIsKeyword */',
|
||||
'T_TRAIT',
|
||||
],
|
||||
[
|
||||
'/* testEnumIsKeyword */',
|
||||
'T_ENUM',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testNewIsKeyword */',
|
||||
'T_NEW',
|
||||
],
|
||||
[
|
||||
'/* testInstanceOfIsKeyword */',
|
||||
'T_INSTANCEOF',
|
||||
],
|
||||
[
|
||||
'/* testCloneIsKeyword */',
|
||||
'T_CLONE',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testIfIsKeyword */',
|
||||
'T_IF',
|
||||
],
|
||||
[
|
||||
'/* testEmptyIsKeyword */',
|
||||
'T_EMPTY',
|
||||
],
|
||||
[
|
||||
'/* testElseIfIsKeyword */',
|
||||
'T_ELSEIF',
|
||||
],
|
||||
[
|
||||
'/* testElseIsKeyword */',
|
||||
'T_ELSE',
|
||||
],
|
||||
[
|
||||
'/* testEndIfIsKeyword */',
|
||||
'T_ENDIF',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testForIsKeyword */',
|
||||
'T_FOR',
|
||||
],
|
||||
[
|
||||
'/* testEndForIsKeyword */',
|
||||
'T_ENDFOR',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testForeachIsKeyword */',
|
||||
'T_FOREACH',
|
||||
],
|
||||
[
|
||||
'/* testEndForeachIsKeyword */',
|
||||
'T_ENDFOREACH',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testSwitchIsKeyword */',
|
||||
'T_SWITCH',
|
||||
],
|
||||
[
|
||||
'/* testCaseIsKeyword */',
|
||||
'T_CASE',
|
||||
],
|
||||
[
|
||||
'/* testDefaultIsKeyword */',
|
||||
'T_DEFAULT',
|
||||
],
|
||||
[
|
||||
'/* testEndSwitchIsKeyword */',
|
||||
'T_ENDSWITCH',
|
||||
],
|
||||
[
|
||||
'/* testBreakIsKeyword */',
|
||||
'T_BREAK',
|
||||
],
|
||||
[
|
||||
'/* testContinueIsKeyword */',
|
||||
'T_CONTINUE',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testDoIsKeyword */',
|
||||
'T_DO',
|
||||
],
|
||||
[
|
||||
'/* testWhileIsKeyword */',
|
||||
'T_WHILE',
|
||||
],
|
||||
[
|
||||
'/* testEndWhileIsKeyword */',
|
||||
'T_ENDWHILE',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testTryIsKeyword */',
|
||||
'T_TRY',
|
||||
],
|
||||
[
|
||||
'/* testThrowIsKeyword */',
|
||||
'T_THROW',
|
||||
],
|
||||
[
|
||||
'/* testCatchIsKeyword */',
|
||||
'T_CATCH',
|
||||
],
|
||||
[
|
||||
'/* testFinallyIsKeyword */',
|
||||
'T_FINALLY',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testGlobalIsKeyword */',
|
||||
'T_GLOBAL',
|
||||
],
|
||||
[
|
||||
'/* testEchoIsKeyword */',
|
||||
'T_ECHO',
|
||||
],
|
||||
[
|
||||
'/* testPrintIsKeyword */',
|
||||
'T_PRINT',
|
||||
],
|
||||
[
|
||||
'/* testDieIsKeyword */',
|
||||
'T_EXIT',
|
||||
],
|
||||
[
|
||||
'/* testEvalIsKeyword */',
|
||||
'T_EVAL',
|
||||
],
|
||||
[
|
||||
'/* testExitIsKeyword */',
|
||||
'T_EXIT',
|
||||
],
|
||||
[
|
||||
'/* testIssetIsKeyword */',
|
||||
'T_ISSET',
|
||||
],
|
||||
[
|
||||
'/* testUnsetIsKeyword */',
|
||||
'T_UNSET',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testIncludeIsKeyword */',
|
||||
'T_INCLUDE',
|
||||
],
|
||||
[
|
||||
'/* testIncludeOnceIsKeyword */',
|
||||
'T_INCLUDE_ONCE',
|
||||
],
|
||||
[
|
||||
'/* testRequireIsKeyword */',
|
||||
'T_REQUIRE',
|
||||
],
|
||||
[
|
||||
'/* testRequireOnceIsKeyword */',
|
||||
'T_REQUIRE_ONCE',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testListIsKeyword */',
|
||||
'T_LIST',
|
||||
],
|
||||
[
|
||||
'/* testGotoIsKeyword */',
|
||||
'T_GOTO',
|
||||
],
|
||||
[
|
||||
'/* testMatchIsKeyword */',
|
||||
'T_MATCH',
|
||||
],
|
||||
[
|
||||
'/* testMatchDefaultIsKeyword */',
|
||||
'T_MATCH_DEFAULT',
|
||||
],
|
||||
[
|
||||
'/* testFnIsKeyword */',
|
||||
'T_FN',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testYieldIsKeyword */',
|
||||
'T_YIELD',
|
||||
],
|
||||
[
|
||||
'/* testYieldFromIsKeyword */',
|
||||
'T_YIELD_FROM',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testDeclareIsKeyword */',
|
||||
'T_DECLARE',
|
||||
],
|
||||
[
|
||||
'/* testEndDeclareIsKeyword */',
|
||||
'T_ENDDECLARE',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testAndIsKeyword */',
|
||||
'T_LOGICAL_AND',
|
||||
],
|
||||
[
|
||||
'/* testOrIsKeyword */',
|
||||
'T_LOGICAL_OR',
|
||||
],
|
||||
[
|
||||
'/* testXorIsKeyword */',
|
||||
'T_LOGICAL_XOR',
|
||||
],
|
||||
|
||||
[
|
||||
'/* testAnonymousClassIsKeyword */',
|
||||
'T_ANON_CLASS',
|
||||
],
|
||||
[
|
||||
'/* testExtendsInAnonymousClassIsKeyword */',
|
||||
'T_EXTENDS',
|
||||
],
|
||||
[
|
||||
'/* testImplementsInAnonymousClassIsKeyword */',
|
||||
'T_IMPLEMENTS',
|
||||
],
|
||||
[
|
||||
'/* testClassInstantiationParentIsKeyword */',
|
||||
'T_PARENT',
|
||||
],
|
||||
[
|
||||
'/* testClassInstantiationSelfIsKeyword */',
|
||||
'T_SELF',
|
||||
],
|
||||
[
|
||||
'/* testClassInstantiationStaticIsKeyword */',
|
||||
'T_STATIC',
|
||||
],
|
||||
[
|
||||
'/* testNamespaceInNameIsKeyword */',
|
||||
'T_NAMESPACE',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataKeywords()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+203
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
function matchWithDefault($i) {
|
||||
return match ($i) {
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
/* testSimpleMatchDefault */
|
||||
default => 'default',
|
||||
};
|
||||
}
|
||||
|
||||
function switchWithDefault($i) {
|
||||
switch ($i) {
|
||||
case 1:
|
||||
return 1;
|
||||
case 2:
|
||||
return 2;
|
||||
/* testSimpleSwitchDefault */
|
||||
default:
|
||||
return 'default';
|
||||
}
|
||||
}
|
||||
|
||||
function switchWithDefaultAndCurlies($i) {
|
||||
switch ($i) {
|
||||
case 1:
|
||||
return 1;
|
||||
case 2:
|
||||
return 2;
|
||||
/* testSimpleSwitchDefaultWithCurlies */
|
||||
default: {
|
||||
return 'default';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function matchWithDefaultInSwitch() {
|
||||
switch ($something) {
|
||||
case 'foo':
|
||||
$var = [1, 2, 3];
|
||||
$var = match ($i) {
|
||||
1 => 1,
|
||||
/* testMatchDefaultNestedInSwitchCase1 */
|
||||
default => 'default',
|
||||
};
|
||||
continue;
|
||||
|
||||
case 'bar' :
|
||||
$i = callMe($a, $b);
|
||||
return match ($i) {
|
||||
1 => 1,
|
||||
/* testMatchDefaultNestedInSwitchCase2 */
|
||||
default => 'default',
|
||||
};
|
||||
|
||||
/* testSwitchDefault */
|
||||
default;
|
||||
echo 'something', match ($i) {
|
||||
1, => 1,
|
||||
/* testMatchDefaultNestedInSwitchDefault */
|
||||
default, => 'default',
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function switchWithDefaultInMatch() {
|
||||
$x = match ($y) {
|
||||
5, 8 => function($z) {
|
||||
switch($z) {
|
||||
case 'a';
|
||||
$var = [1, 2, 3];
|
||||
return 'a';
|
||||
/* testSwitchDefaultNestedInMatchCase */
|
||||
default:
|
||||
$var = [1, 2, 3];
|
||||
return 'default1';
|
||||
}
|
||||
},
|
||||
/* testMatchDefault */
|
||||
default => function($z) {
|
||||
switch($z) {
|
||||
case 'a':
|
||||
$i = callMe($a, $b);
|
||||
return 'b';
|
||||
/* testSwitchDefaultNestedInMatchDefault */
|
||||
default:
|
||||
$i = callMe($a, $b);
|
||||
return 'default2';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function shortArrayWithConstantKey() {
|
||||
$arr = [
|
||||
/* testClassConstantAsShortArrayKey */
|
||||
SomeClass::DEFAULT => 1,
|
||||
/* testClassPropertyAsShortArrayKey */
|
||||
SomeClass->DEFAULT => 1,
|
||||
/* testNamespacedConstantAsShortArrayKey */
|
||||
// Intentional parse error PHP < 8.0. Reserved keyword used as namespaced constant.
|
||||
SomeNamespace\DEFAULT => 1,
|
||||
/* testFQNGlobalConstantAsShortArrayKey */
|
||||
// Intentional parse error in PHP < 8.0. Reserved keyword used as global constant.
|
||||
\DEFAULT => 1,
|
||||
];
|
||||
}
|
||||
|
||||
function longArrayWithConstantKey() {
|
||||
$arr = array(
|
||||
/* testClassConstantAsLongArrayKey */
|
||||
SomeClass::DEFAULT => 1,
|
||||
);
|
||||
}
|
||||
|
||||
function yieldWithConstantKey() {
|
||||
/* testClassConstantAsYieldKey */
|
||||
yield SomeClass::DEFAULT => 1;
|
||||
}
|
||||
|
||||
function longArrayWithConstantKeyNestedInMatch() {
|
||||
return match($x) {
|
||||
/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */
|
||||
DEFAULT => array(
|
||||
/* testClassConstantAsLongArrayKeyNestedInMatch */
|
||||
SomeClass::DEFAULT => match($x) {
|
||||
/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */
|
||||
DEFAULT => array(
|
||||
/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */
|
||||
SomeClass::DEFAULT => 1,
|
||||
),
|
||||
},
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
function shortArrayWithConstantKeyNestedInMatch() {
|
||||
return match($x) {
|
||||
/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */
|
||||
DEFAULT => [
|
||||
/* testClassConstantAsShortArrayKeyNestedInMatch */
|
||||
SomeClass::DEFAULT => match($x) {
|
||||
/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */
|
||||
DEFAULT => [
|
||||
/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */
|
||||
SomeClass::DEFAULT => 1,
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function longArrayWithConstantKeyWithNestedMatch() {
|
||||
return array(
|
||||
/* testClassConstantAsLongArrayKeyWithNestedMatch */
|
||||
SomeClass::DEFAULT => match($x) {
|
||||
/* testMatchDefaultNestedInLongArray */
|
||||
DEFAULT => 'foo'
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function shortArrayWithConstantKeyWithNestedMatch() {
|
||||
return [
|
||||
/* testClassConstantAsShortArrayKeyWithNestedMatch */
|
||||
SomeClass::DEFAULT => match($x) {
|
||||
/* testMatchDefaultNestedInShortArray */
|
||||
DEFAULT => 'foo'
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function switchWithConstantNonDefault($i) {
|
||||
switch ($i) {
|
||||
/* testClassConstantInSwitchCase */
|
||||
case SomeClass::DEFAULT:
|
||||
return 1;
|
||||
|
||||
/* testClassPropertyInSwitchCase */
|
||||
case SomeClass->DEFAULT:
|
||||
return 2;
|
||||
|
||||
/* testNamespacedConstantInSwitchCase */
|
||||
// Intentional parse error PHP < 8.0. Reserved keyword used as constant.
|
||||
case SomeNamespace\DEFAULT:
|
||||
return 2;
|
||||
|
||||
/* testNamespaceRelativeConstantInSwitchCase */
|
||||
// Intentional parse error PHP < 8.0. Reserved keyword used as global constant.
|
||||
case namespace\DEFAULT:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
/* testClassConstant */
|
||||
const DEFAULT = 'foo';
|
||||
|
||||
/* testMethodDeclaration */
|
||||
public function default() {}
|
||||
}
|
||||
Vendored
+302
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the retokenization of the `default` keyword to T_MATCH_DEFAULT for PHP 8.0 match structures
|
||||
* and makes sure that the tokenization of switch `T_DEFAULT` structures is not aversely affected.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class DefaultKeywordTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test the retokenization of the `default` keyword for match structure to `T_MATCH_DEFAULT`.
|
||||
*
|
||||
* Note: Cases and default structures within a match structure do *NOT* get case/default scope
|
||||
* conditions, in contrast to case and default structures in switch control structures.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataMatchDefault
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchDefault($testMarker, $testContent='default')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_MATCH_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (code)');
|
||||
$this->assertSame('T_MATCH_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (type)');
|
||||
|
||||
$this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set');
|
||||
$this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set');
|
||||
$this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set');
|
||||
|
||||
}//end testMatchDefault()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testMatchDefault()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataMatchDefault()
|
||||
{
|
||||
return [
|
||||
'simple_match_default' => ['/* testSimpleMatchDefault */'],
|
||||
'match_default_in_switch_case_1' => ['/* testMatchDefaultNestedInSwitchCase1 */'],
|
||||
'match_default_in_switch_case_2' => ['/* testMatchDefaultNestedInSwitchCase2 */'],
|
||||
'match_default_in_switch_default' => ['/* testMatchDefaultNestedInSwitchDefault */'],
|
||||
'match_default_containing_switch' => ['/* testMatchDefault */'],
|
||||
|
||||
'match_default_with_nested_long_array_and_default_key' => [
|
||||
'/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */',
|
||||
'DEFAULT',
|
||||
],
|
||||
'match_default_with_nested_long_array_and_default_key_2' => [
|
||||
'/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */',
|
||||
'DEFAULT',
|
||||
],
|
||||
'match_default_with_nested_short_array_and_default_key' => [
|
||||
'/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */',
|
||||
'DEFAULT',
|
||||
],
|
||||
'match_default_with_nested_short_array_and_default_key_2' => [
|
||||
'/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */',
|
||||
'DEFAULT',
|
||||
],
|
||||
'match_default_in_long_array' => [
|
||||
'/* testMatchDefaultNestedInLongArray */',
|
||||
'DEFAULT',
|
||||
],
|
||||
'match_default_in_short_array' => [
|
||||
'/* testMatchDefaultNestedInShortArray */',
|
||||
'DEFAULT',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataMatchDefault()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively
|
||||
* impact the tokenization of `T_DEFAULT` tokens in switch control structures.
|
||||
*
|
||||
* Note: Cases and default structures within a switch control structure *do* get case/default scope
|
||||
* conditions.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param int $openerOffset The expected offset of the scope opener in relation to the testMarker.
|
||||
* @param int $closerOffset The expected offset of the scope closer in relation to the testMarker.
|
||||
* @param int|null $conditionStop The expected offset at which tokens stop having T_DEFAULT as a scope condition.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataSwitchDefault
|
||||
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSwitchDefault($testMarker, $openerOffset, $closerOffset, $conditionStop=null, $testContent='default')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent);
|
||||
$tokenArray = $tokens[$token];
|
||||
$expectedScopeOpener = ($token + $openerOffset);
|
||||
$expectedScopeCloser = ($token + $closerOffset);
|
||||
|
||||
$this->assertSame(T_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (code)');
|
||||
$this->assertSame('T_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (type)');
|
||||
|
||||
$this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set');
|
||||
$this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set');
|
||||
$this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set');
|
||||
$this->assertSame($token, $tokenArray['scope_condition'], 'Scope condition is not the T_DEFAULT token');
|
||||
$this->assertSame($expectedScopeOpener, $tokenArray['scope_opener'], 'Scope opener of the T_DEFAULT token incorrect');
|
||||
$this->assertSame($expectedScopeCloser, $tokenArray['scope_closer'], 'Scope closer of the T_DEFAULT token incorrect');
|
||||
|
||||
$opener = $tokenArray['scope_opener'];
|
||||
$this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set');
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set');
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set');
|
||||
$this->assertSame($token, $tokens[$opener]['scope_condition'], 'Opener scope condition is not the T_DEFAULT token');
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'T_DEFAULT opener scope opener token incorrect');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'T_DEFAULT opener scope closer token incorrect');
|
||||
|
||||
$closer = $tokenArray['scope_closer'];
|
||||
$this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set');
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set');
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set');
|
||||
$this->assertSame($token, $tokens[$closer]['scope_condition'], 'Closer scope condition is not the T_DEFAULT token');
|
||||
$this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'T_DEFAULT closer scope opener token incorrect');
|
||||
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'T_DEFAULT closer scope closer token incorrect');
|
||||
|
||||
if (($opener + 1) !== $closer) {
|
||||
$end = $closer;
|
||||
if (isset($conditionStop) === true) {
|
||||
$end = $conditionStop;
|
||||
}
|
||||
|
||||
for ($i = ($opener + 1); $i < $end; $i++) {
|
||||
$this->assertArrayHasKey(
|
||||
$token,
|
||||
$tokens[$i]['conditions'],
|
||||
'T_DEFAULT condition not added for token belonging to the T_DEFAULT structure'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}//end testSwitchDefault()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testSwitchDefault()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataSwitchDefault()
|
||||
{
|
||||
return [
|
||||
'simple_switch_default' => [
|
||||
'/* testSimpleSwitchDefault */',
|
||||
1,
|
||||
4,
|
||||
],
|
||||
'simple_switch_default_with_curlies' => [
|
||||
// For a default structure with curly braces, the scope opener
|
||||
// will be the open curly and the closer the close curly.
|
||||
// However, scope conditions will not be set for open to close,
|
||||
// but only for the open token up to the "break/return/continue" etc.
|
||||
'/* testSimpleSwitchDefaultWithCurlies */',
|
||||
3,
|
||||
12,
|
||||
6,
|
||||
],
|
||||
'switch_default_toplevel' => [
|
||||
'/* testSwitchDefault */',
|
||||
1,
|
||||
43,
|
||||
],
|
||||
'switch_default_nested_in_match_case' => [
|
||||
'/* testSwitchDefaultNestedInMatchCase */',
|
||||
1,
|
||||
20,
|
||||
],
|
||||
'switch_default_nested_in_match_default' => [
|
||||
'/* testSwitchDefaultNestedInMatchDefault */',
|
||||
1,
|
||||
18,
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataSwitchDefault()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively
|
||||
* impact the tokenization of `T_STRING` tokens with the contents 'default' which aren't in
|
||||
* actual fact the default keyword.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataNotDefaultKeyword
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT')
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)');
|
||||
$this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)');
|
||||
|
||||
$this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set');
|
||||
$this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set');
|
||||
$this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set');
|
||||
|
||||
}//end testNotDefaultKeyword()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNotDefaultKeyword()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNotDefaultKeyword()
|
||||
{
|
||||
return [
|
||||
'class-constant-as-short-array-key' => ['/* testClassConstantAsShortArrayKey */'],
|
||||
'class-property-as-short-array-key' => ['/* testClassPropertyAsShortArrayKey */'],
|
||||
'namespaced-constant-as-short-array-key' => ['/* testNamespacedConstantAsShortArrayKey */'],
|
||||
'fqn-global-constant-as-short-array-key' => ['/* testFQNGlobalConstantAsShortArrayKey */'],
|
||||
'class-constant-as-long-array-key' => ['/* testClassConstantAsLongArrayKey */'],
|
||||
'class-constant-as-yield-key' => ['/* testClassConstantAsYieldKey */'],
|
||||
|
||||
'class-constant-as-long-array-key-nested-in-match' => ['/* testClassConstantAsLongArrayKeyNestedInMatch */'],
|
||||
'class-constant-as-long-array-key-nested-in-match-2' => ['/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */'],
|
||||
'class-constant-as-short-array-key-nested-in-match' => ['/* testClassConstantAsShortArrayKeyNestedInMatch */'],
|
||||
'class-constant-as-short-array-key-nested-in-match-2' => ['/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */'],
|
||||
'class-constant-as-long-array-key-with-nested-match' => ['/* testClassConstantAsLongArrayKeyWithNestedMatch */'],
|
||||
'class-constant-as-short-array-key-with-nested-match' => ['/* testClassConstantAsShortArrayKeyWithNestedMatch */'],
|
||||
|
||||
'class-constant-in-switch-case' => ['/* testClassConstantInSwitchCase */'],
|
||||
'class-property-in-switch-case' => ['/* testClassPropertyInSwitchCase */'],
|
||||
'namespaced-constant-in-switch-case' => ['/* testNamespacedConstantInSwitchCase */'],
|
||||
'namespace-relative-constant-in-switch-case' => ['/* testNamespaceRelativeConstantInSwitchCase */'],
|
||||
|
||||
'class-constant-declaration' => ['/* testClassConstant */'],
|
||||
'class-method-declaration' => [
|
||||
'/* testMethodDeclaration */',
|
||||
'default',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataNotDefaultKeyword()
|
||||
|
||||
|
||||
/**
|
||||
* Test a specific edge case where a scope opener would be incorrectly set.
|
||||
*
|
||||
* @link https://github.com/squizlabs/PHP_CodeSniffer/issues/3326
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testIssue3326()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testClassConstant */', [T_SEMICOLON]);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set');
|
||||
$this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set');
|
||||
$this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set');
|
||||
|
||||
}//end testIssue3326()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+281
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
function simpleLongArray($x) {
|
||||
return array(
|
||||
/* testLongArrayArrowSimple */
|
||||
0 => 'Zero',
|
||||
);
|
||||
}
|
||||
|
||||
function simpleShortArray($x) {
|
||||
return [
|
||||
/* testShortArrayArrowSimple */
|
||||
0 => 'Zero',
|
||||
];
|
||||
}
|
||||
|
||||
function simpleLongList($x) {
|
||||
list(
|
||||
/* testLongListArrowSimple */
|
||||
0 => $a,
|
||||
) = $x;
|
||||
}
|
||||
|
||||
function simpleShortList($x) {
|
||||
[
|
||||
/* testShortListArrowSimple */
|
||||
0 => $a,
|
||||
] = $x;
|
||||
}
|
||||
|
||||
function simpleYield($x) {
|
||||
$i = 0;
|
||||
foreach (explode("\n", $x) as $line) {
|
||||
/* testYieldArrowSimple */
|
||||
yield ++$i => $line;
|
||||
}
|
||||
}
|
||||
|
||||
function simpleForeach($x) {
|
||||
/* testForeachArrowSimple */
|
||||
foreach ($x as $k => $value) {}
|
||||
}
|
||||
|
||||
function simpleMatch($x) {
|
||||
return match ($x) {
|
||||
/* testMatchArrowSimpleSingleCase */
|
||||
0 => 'Zero',
|
||||
/* testMatchArrowSimpleMultiCase */
|
||||
2, 4, 6 => 'Zero',
|
||||
/* testMatchArrowSimpleSingleCaseWithTrailingComma */
|
||||
1, => 'Zero',
|
||||
/* testMatchArrowSimpleMultiCaseWithTrailingComma */
|
||||
3, 5, => 'Zero',
|
||||
};
|
||||
}
|
||||
|
||||
function simpleArrowFunction($y) {
|
||||
/* testFnArrowSimple */
|
||||
return fn ($y) => callMe($y);
|
||||
}
|
||||
|
||||
function matchNestedInMatch() {
|
||||
$x = match ($y) {
|
||||
/* testMatchArrowNestedMatchOuter */
|
||||
default, => match ($z) {
|
||||
/* testMatchArrowNestedMatchInner */
|
||||
1 => 1
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function matchNestedInLongArrayValue() {
|
||||
$array = array(
|
||||
/* testLongArrayArrowWithNestedMatchValue1 */
|
||||
'a' => match ($test) {
|
||||
/* testMatchArrowInLongArrayValue1 */
|
||||
1 => 'a',
|
||||
/* testMatchArrowInLongArrayValue2 */
|
||||
2 => 'b'
|
||||
},
|
||||
/* testLongArrayArrowWithNestedMatchValue2 */
|
||||
$i => match ($test) {
|
||||
/* testMatchArrowInLongArrayValue3 */
|
||||
1 => 'a',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function matchNestedInShortArrayValue() {
|
||||
$array = [
|
||||
/* testShortArrayArrowWithNestedMatchValue1 */
|
||||
'a' => match ($test) {
|
||||
/* testMatchArrowInShortArrayValue1 */
|
||||
1 => 'a',
|
||||
/* testMatchArrowInShortArrayValue2 */
|
||||
2 => 'b'
|
||||
},
|
||||
/* testShortArrayArrowWithNestedMatchValue2 */
|
||||
$i => match ($test) {
|
||||
/* testMatchArrowInShortArrayValue3 */
|
||||
1 => 'a',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function matchNestedInLongArrayKey() {
|
||||
$array = array(
|
||||
match ($test) { /* testMatchArrowInLongArrayKey1 */ 1 => 'a', /* testMatchArrowInLongArrayKey2 */ 2 => 'b' }
|
||||
/* testLongArrayArrowWithMatchKey */
|
||||
=> 'dynamic keys, woho!',
|
||||
);
|
||||
}
|
||||
|
||||
function matchNestedInShortArrayKey() {
|
||||
$array = [
|
||||
match ($test) { /* testMatchArrowInShortArrayKey1 */ 1 => 'a', /* testMatchArrowInShortArrayKey2 */ 2 => 'b' }
|
||||
/* testShortArrayArrowWithMatchKey */
|
||||
=> 'dynamic keys, woho!',
|
||||
];
|
||||
}
|
||||
|
||||
function arraysNestedInMatch() {
|
||||
$matcher = match ($x) {
|
||||
/* testMatchArrowWithLongArrayBodyWithKeys */
|
||||
0 => array(
|
||||
/* testLongArrayArrowInMatchBody1 */
|
||||
0 => 1,
|
||||
/* testLongArrayArrowInMatchBody2 */
|
||||
'a' => 2,
|
||||
/* testLongArrayArrowInMatchBody3 */
|
||||
'b' => 3
|
||||
),
|
||||
/* testMatchArrowWithShortArrayBodyWithoutKeys */
|
||||
1 => [1, 2, 3],
|
||||
/* testMatchArrowWithLongArrayBodyWithoutKeys */
|
||||
2 => array( 1, [1, 2, 3], 2, 3),
|
||||
/* testMatchArrowWithShortArrayBodyWithKeys */
|
||||
3 => [
|
||||
/* testShortArrayArrowInMatchBody1 */
|
||||
0 => 1,
|
||||
/* testShortArrayArrowInMatchBody2 */
|
||||
'a' => array(1, 2, 3),
|
||||
/* testShortArrayArrowInMatchBody3 */
|
||||
'b' => 2,
|
||||
3
|
||||
],
|
||||
/* testShortArrayArrowinMatchCase1 */
|
||||
[4 => 'a', /* testShortArrayArrowinMatchCase2 */ 5 => 6]
|
||||
/* testMatchArrowWithShortArrayWithKeysAsCase */
|
||||
=> 'match with array as case value',
|
||||
/* testShortArrayArrowinMatchCase3 */
|
||||
[4 => 'a'], /* testLongArrayArrowinMatchCase4 */ array(5 => 6),
|
||||
/* testMatchArrowWithMultipleArraysWithKeysAsCase */
|
||||
=> 'match with multiple arrays as case value',
|
||||
};
|
||||
}
|
||||
|
||||
function matchNestedInArrowFunction($x) {
|
||||
/* testFnArrowWithMatchInValue */
|
||||
$fn = fn($x) => match(true) {
|
||||
/* testMatchArrowInFnBody1 */
|
||||
1, 2, 3, 4, 5 => 'foo',
|
||||
/* testMatchArrowInFnBody2 */
|
||||
default => 'bar',
|
||||
};
|
||||
}
|
||||
|
||||
function arrowFunctionsNestedInMatch($x) {
|
||||
return match ($x) {
|
||||
/* testMatchArrowWithFnBody1 */
|
||||
1 => /* testFnArrowInMatchBody1 */ fn($y) => callMe($y),
|
||||
/* testMatchArrowWithFnBody2 */
|
||||
default => /* testFnArrowInMatchBody2 */ fn($y) => callThem($y)
|
||||
};
|
||||
}
|
||||
|
||||
function matchShortArrayMismash() {
|
||||
$array = [
|
||||
match ($test) {
|
||||
/* testMatchArrowInComplexShortArrayKey1 */
|
||||
1 => [ /* testShortArrayArrowInComplexMatchValueinShortArrayKey */ 1 => 'a'],
|
||||
/* testMatchArrowInComplexShortArrayKey2 */
|
||||
2 => 'b'
|
||||
/* testShortArrayArrowInComplexMatchArrayMismash */
|
||||
} => match ($test) {
|
||||
/* testMatchArrowInComplexShortArrayValue1 */
|
||||
1 => [ /* testShortArrayArrowInComplexMatchValueinShortArrayValue */ 1 => 'a'],
|
||||
/* testMatchArrowInComplexShortArrayValue2 */
|
||||
2 => /* testFnArrowInComplexMatchValueInShortArrayValue */ fn($y) => callMe($y)
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
function longListInMatch($x, $y) {
|
||||
return match($x) {
|
||||
/* testMatchArrowWithLongListBody */
|
||||
1 => list('a' => $a, /* testLongListArrowInMatchBody */ 'b' => $b, 'c' => list('d' => $c)) = $y,
|
||||
/* testLongListArrowInMatchCase */
|
||||
list('a' => $a, 'b' => $b) = $y /* testMatchArrowWithLongListInCase */ => 'something'
|
||||
};
|
||||
}
|
||||
|
||||
function shortListInMatch($x, $y) {
|
||||
return match($x) {
|
||||
/* testMatchArrowWithShortListBody */
|
||||
1 => ['a' => $a, 'b' => $b, 'c' => /* testShortListArrowInMatchBody */ ['d' => $c]] = $y,
|
||||
/* testShortListArrowInMatchCase */
|
||||
['a' => $a, 'b' => $b] = $y /* testMatchArrowWithShortListInCase */ => 'something'
|
||||
};
|
||||
}
|
||||
|
||||
function matchInLongList() {
|
||||
/* testMatchArrowInLongListKey */
|
||||
list(match($x) {1 => 1, 2 => 2} /* testLongListArrowWithMatchInKey */ => $a) = $array;
|
||||
}
|
||||
|
||||
function matchInShortList() {
|
||||
/* testMatchArrowInShortListKey */
|
||||
[match($x) {1 => 1, 2 => 2} /* testShortListArrowWithMatchInKey */ => $a] = $array;
|
||||
}
|
||||
|
||||
function longArrayWithConstantKey() {
|
||||
$arr = array(
|
||||
/* testLongArrayArrowWithClassConstantKey */
|
||||
SomeClass::DEFAULT => 1,
|
||||
);
|
||||
}
|
||||
|
||||
function shortArrayWithConstantKey() {
|
||||
$arr = [
|
||||
/* testShortArrayArrowWithClassConstantKey */
|
||||
SomeClass::DEFAULT => 1,
|
||||
];
|
||||
}
|
||||
|
||||
function yieldWithConstantKey() {
|
||||
/* testYieldArrowWithClassConstantKey */
|
||||
yield SomeClass::DEFAULT => 1;
|
||||
}
|
||||
|
||||
function longArrayWithConstantKeyNestedInMatch() {
|
||||
return match($x) {
|
||||
/* testMatchArrowWithNestedLongArrayWithClassConstantKey */
|
||||
default => array(
|
||||
/* testLongArrayArrowWithClassConstantKeyNestedInMatch */
|
||||
SomeClass::DEFAULT => 1,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
function shortArrayWithConstantKeyNestedInMatch() {
|
||||
return match($x) {
|
||||
/* testMatchArrowWithNestedShortArrayWithClassConstantKey */
|
||||
default => [
|
||||
/* testShortArrayArrowWithClassConstantKeyNestedInMatch */
|
||||
SomeClass::DEFAULT => 1,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function longArrayWithConstantKeyWithNestedMatch() {
|
||||
return array(
|
||||
/* testLongArrayArrowWithClassConstantKeyWithNestedMatch */
|
||||
SomeClass::DEFAULT => match($x) {
|
||||
/* testMatchArrowNestedInLongArrayWithClassConstantKey */
|
||||
default => 'foo'
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function shortArrayWithConstantKeyWithNestedMatch() {
|
||||
return [
|
||||
/* testShortArrayArrowWithClassConstantKeyWithNestedMatch */
|
||||
SomeClass::DEFAULT => match($x) {
|
||||
/* testMatchArrowNestedInShortArrayWithClassConstantKey */
|
||||
default => 'foo'
|
||||
},
|
||||
];
|
||||
}
|
||||
Vendored
+237
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the retokenization of the double arrow to T_MATCH_ARROW for PHP 8.0 match structures
|
||||
* and makes sure that the tokenization of other double arrows (array, arrow function, yield)
|
||||
* is not aversely affected.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class DoubleArrowTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that "normal" double arrows are correctly tokenized as `T_DOUBLE_ARROW`.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
*
|
||||
* @dataProvider dataDoubleArrow
|
||||
* @coversNothing
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDoubleArrow($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_DOUBLE_ARROW, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_DOUBLE_ARROW (code)');
|
||||
$this->assertSame('T_DOUBLE_ARROW', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_DOUBLE_ARROW (type)');
|
||||
|
||||
}//end testDoubleArrow()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testDoubleArrow()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataDoubleArrow()
|
||||
{
|
||||
return [
|
||||
'simple_long_array' => ['/* testLongArrayArrowSimple */'],
|
||||
'simple_short_array' => ['/* testShortArrayArrowSimple */'],
|
||||
'simple_long_list' => ['/* testLongListArrowSimple */'],
|
||||
'simple_short_list' => ['/* testShortListArrowSimple */'],
|
||||
'simple_yield' => ['/* testYieldArrowSimple */'],
|
||||
'simple_foreach' => ['/* testForeachArrowSimple */'],
|
||||
|
||||
'long_array_with_match_value_1' => ['/* testLongArrayArrowWithNestedMatchValue1 */'],
|
||||
'long_array_with_match_value_2' => ['/* testLongArrayArrowWithNestedMatchValue2 */'],
|
||||
'short_array_with_match_value_1' => ['/* testShortArrayArrowWithNestedMatchValue1 */'],
|
||||
'short_array_with_match_value_2' => ['/* testShortArrayArrowWithNestedMatchValue2 */'],
|
||||
|
||||
'long_array_with_match_key' => ['/* testLongArrayArrowWithMatchKey */'],
|
||||
'short_array_with_match_key' => ['/* testShortArrayArrowWithMatchKey */'],
|
||||
|
||||
'long_array_in_match_body_1' => ['/* testLongArrayArrowInMatchBody1 */'],
|
||||
'long_array_in_match_body_2' => ['/* testLongArrayArrowInMatchBody2 */'],
|
||||
'long_array_in_match_body_3' => ['/* testLongArrayArrowInMatchBody3 */'],
|
||||
'short_array_in_match_body_1' => ['/* testShortArrayArrowInMatchBody1 */'],
|
||||
'short_array_in_match_body_2' => ['/* testShortArrayArrowInMatchBody2 */'],
|
||||
'short_array_in_match_body_3' => ['/* testShortArrayArrowInMatchBody3 */'],
|
||||
|
||||
'short_array_in_match_case_1' => ['/* testShortArrayArrowinMatchCase1 */'],
|
||||
'short_array_in_match_case_2' => ['/* testShortArrayArrowinMatchCase2 */'],
|
||||
'short_array_in_match_case_3' => ['/* testShortArrayArrowinMatchCase3 */'],
|
||||
'long_array_in_match_case_4' => ['/* testLongArrayArrowinMatchCase4 */'],
|
||||
|
||||
'in_complex_short_array_key_match_value' => ['/* testShortArrayArrowInComplexMatchValueinShortArrayKey */'],
|
||||
'in_complex_short_array_toplevel' => ['/* testShortArrayArrowInComplexMatchArrayMismash */'],
|
||||
'in_complex_short_array_value_match_value' => ['/* testShortArrayArrowInComplexMatchValueinShortArrayValue */'],
|
||||
|
||||
'long_list_in_match_body' => ['/* testLongListArrowInMatchBody */'],
|
||||
'long_list_in_match_case' => ['/* testLongListArrowInMatchCase */'],
|
||||
'short_list_in_match_body' => ['/* testShortListArrowInMatchBody */'],
|
||||
'short_list_in_match_case' => ['/* testShortListArrowInMatchCase */'],
|
||||
'long_list_with_match_in_key' => ['/* testLongListArrowWithMatchInKey */'],
|
||||
'short_list_with_match_in_key' => ['/* testShortListArrowWithMatchInKey */'],
|
||||
|
||||
'long_array_with_constant_default_in_key' => ['/* testLongArrayArrowWithClassConstantKey */'],
|
||||
'short_array_with_constant_default_in_key' => ['/* testShortArrayArrowWithClassConstantKey */'],
|
||||
'yield_with_constant_default_in_key' => ['/* testYieldArrowWithClassConstantKey */'],
|
||||
|
||||
'long_array_with_default_in_key_in_match' => ['/* testLongArrayArrowWithClassConstantKeyNestedInMatch */'],
|
||||
'short_array_with_default_in_key_in_match' => ['/* testShortArrayArrowWithClassConstantKeyNestedInMatch */'],
|
||||
'long_array_with_default_in_key_with_match' => ['/* testLongArrayArrowWithClassConstantKeyWithNestedMatch */'],
|
||||
'short_array_with_default_in_key_with_match' => ['/* testShortArrayArrowWithClassConstantKeyWithNestedMatch */'],
|
||||
];
|
||||
|
||||
}//end dataDoubleArrow()
|
||||
|
||||
|
||||
/**
|
||||
* Test that double arrows in match expressions which are the demarkation between a case and the return value
|
||||
* are correctly tokenized as `T_MATCH_ARROW`.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
*
|
||||
* @dataProvider dataMatchArrow
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMatchArrow($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_MATCH_ARROW, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_ARROW (code)');
|
||||
$this->assertSame('T_MATCH_ARROW', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_ARROW (type)');
|
||||
|
||||
}//end testMatchArrow()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testMatchArrow()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataMatchArrow()
|
||||
{
|
||||
return [
|
||||
'single_case' => ['/* testMatchArrowSimpleSingleCase */'],
|
||||
'multi_case' => ['/* testMatchArrowSimpleMultiCase */'],
|
||||
'single_case_with_trailing_comma' => ['/* testMatchArrowSimpleSingleCaseWithTrailingComma */'],
|
||||
'multi_case_with_trailing_comma' => ['/* testMatchArrowSimpleMultiCaseWithTrailingComma */'],
|
||||
'match_nested_outer' => ['/* testMatchArrowNestedMatchOuter */'],
|
||||
'match_nested_inner' => ['/* testMatchArrowNestedMatchInner */'],
|
||||
|
||||
'in_long_array_value_1' => ['/* testMatchArrowInLongArrayValue1 */'],
|
||||
'in_long_array_value_2' => ['/* testMatchArrowInLongArrayValue2 */'],
|
||||
'in_long_array_value_3' => ['/* testMatchArrowInLongArrayValue3 */'],
|
||||
'in_short_array_value_1' => ['/* testMatchArrowInShortArrayValue1 */'],
|
||||
'in_short_array_value_2' => ['/* testMatchArrowInShortArrayValue2 */'],
|
||||
'in_short_array_value_3' => ['/* testMatchArrowInShortArrayValue3 */'],
|
||||
|
||||
'in_long_array_key_1' => ['/* testMatchArrowInLongArrayKey1 */'],
|
||||
'in_long_array_key_2' => ['/* testMatchArrowInLongArrayKey2 */'],
|
||||
'in_short_array_key_1' => ['/* testMatchArrowInShortArrayKey1 */'],
|
||||
'in_short_array_key_2' => ['/* testMatchArrowInShortArrayKey2 */'],
|
||||
|
||||
'with_long_array_value_with_keys' => ['/* testMatchArrowWithLongArrayBodyWithKeys */'],
|
||||
'with_short_array_value_without_keys' => ['/* testMatchArrowWithShortArrayBodyWithoutKeys */'],
|
||||
'with_long_array_value_without_keys' => ['/* testMatchArrowWithLongArrayBodyWithoutKeys */'],
|
||||
'with_short_array_value_with_keys' => ['/* testMatchArrowWithShortArrayBodyWithKeys */'],
|
||||
|
||||
'with_short_array_with_keys_as_case' => ['/* testMatchArrowWithShortArrayWithKeysAsCase */'],
|
||||
'with_multiple_arrays_with_keys_as_case' => ['/* testMatchArrowWithMultipleArraysWithKeysAsCase */'],
|
||||
|
||||
'in_fn_body_case' => ['/* testMatchArrowInFnBody1 */'],
|
||||
'in_fn_body_default' => ['/* testMatchArrowInFnBody2 */'],
|
||||
'with_fn_body_case' => ['/* testMatchArrowWithFnBody1 */'],
|
||||
'with_fn_body_default' => ['/* testMatchArrowWithFnBody2 */'],
|
||||
|
||||
'in_complex_short_array_key_1' => ['/* testMatchArrowInComplexShortArrayKey1 */'],
|
||||
'in_complex_short_array_key_2' => ['/* testMatchArrowInComplexShortArrayKey2 */'],
|
||||
'in_complex_short_array_value_1' => ['/* testMatchArrowInComplexShortArrayValue1 */'],
|
||||
'in_complex_short_array_value_2' => ['/* testMatchArrowInComplexShortArrayValue2 */'],
|
||||
|
||||
'with_long_list_in_body' => ['/* testMatchArrowWithLongListBody */'],
|
||||
'with_long_list_in_case' => ['/* testMatchArrowWithLongListInCase */'],
|
||||
'with_short_list_in_body' => ['/* testMatchArrowWithShortListBody */'],
|
||||
'with_short_list_in_case' => ['/* testMatchArrowWithShortListInCase */'],
|
||||
'in_long_list_key' => ['/* testMatchArrowInLongListKey */'],
|
||||
'in_short_list_key' => ['/* testMatchArrowInShortListKey */'],
|
||||
|
||||
'with_long_array_value_with_default_key' => ['/* testMatchArrowWithNestedLongArrayWithClassConstantKey */'],
|
||||
'with_short_array_value_with_default_key' => ['/* testMatchArrowWithNestedShortArrayWithClassConstantKey */'],
|
||||
'in_long_array_value_with_default_key' => ['/* testMatchArrowNestedInLongArrayWithClassConstantKey */'],
|
||||
'in_short_array_value_with_default_key' => ['/* testMatchArrowNestedInShortArrayWithClassConstantKey */'],
|
||||
];
|
||||
|
||||
}//end dataMatchArrow()
|
||||
|
||||
|
||||
/**
|
||||
* Test that double arrows used as the scope opener for an arrow function
|
||||
* are correctly tokenized as `T_FN_ARROW`.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
*
|
||||
* @dataProvider dataFnArrow
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFnArrow($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]);
|
||||
$tokenArray = $tokens[$token];
|
||||
|
||||
$this->assertSame(T_FN_ARROW, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_FN_ARROW (code)');
|
||||
$this->assertSame('T_FN_ARROW', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_FN_ARROW (type)');
|
||||
|
||||
}//end testFnArrow()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testFnArrow()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataFnArrow()
|
||||
{
|
||||
return [
|
||||
'simple_fn' => ['/* testFnArrowSimple */'],
|
||||
|
||||
'with_match_as_value' => ['/* testFnArrowWithMatchInValue */'],
|
||||
'in_match_value_case' => ['/* testFnArrowInMatchBody1 */'],
|
||||
'in_match_value_default' => ['/* testFnArrowInMatchBody2 */'],
|
||||
|
||||
'in_complex_match_value_in_short_array' => ['/* testFnArrowInComplexMatchValueInShortArrayValue */'],
|
||||
];
|
||||
|
||||
}//end dataFnArrow()
|
||||
|
||||
|
||||
}//end class
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
// Test source: https://gist.github.com/iluuu1994/72e2154fc4150f2258316b0255b698f2#file-test-php
|
||||
|
||||
/* testSimple1 */
|
||||
"$foo";
|
||||
/* testSimple2 */
|
||||
"{$foo}";
|
||||
/* testSimple3 */
|
||||
"${foo}";
|
||||
|
||||
/* testDIM1 */
|
||||
"$foo[bar]";
|
||||
/* testDIM2 */
|
||||
"{$foo['bar']}";
|
||||
/* testDIM3 */
|
||||
"${foo['bar']}";
|
||||
|
||||
/* testProperty1 */
|
||||
"$foo->bar";
|
||||
/* testProperty2 */
|
||||
"{$foo->bar}";
|
||||
|
||||
/* testMethod1 */
|
||||
"{$foo->bar()}";
|
||||
|
||||
/* testClosure1 */
|
||||
"{$foo()}";
|
||||
|
||||
/* testChain1 */
|
||||
"{$foo['bar']->baz()()}";
|
||||
|
||||
/* testVariableVar1 */
|
||||
"${$bar}";
|
||||
/* testVariableVar2 */
|
||||
"${(foo)}";
|
||||
/* testVariableVar3 */
|
||||
"${foo->bar}";
|
||||
|
||||
/* testNested1 */
|
||||
"${foo["${bar}"]}";
|
||||
/* testNested2 */
|
||||
"${foo["${bar['baz']}"]}";
|
||||
/* testNested3 */
|
||||
"${foo->{$baz}}";
|
||||
/* testNested4 */
|
||||
"${foo->{${'a'}}}";
|
||||
/* testNested5 */
|
||||
"${foo->{"${'a'}"}}";
|
||||
|
||||
/* testParseError */
|
||||
"${foo["${bar
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests that embedded variables and expressions in double quoted strings are tokenized
|
||||
* as one double quoted string token.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class DoubleQuotedStringTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that double quoted strings contain the complete string.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param string $expectedContent The expected content of the double quoted string.
|
||||
*
|
||||
* @dataProvider dataDoubleQuotedString
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDoubleQuotedString($testMarker, $expectedContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$target = $this->getTargetToken($testMarker, T_DOUBLE_QUOTED_STRING);
|
||||
$this->assertSame($expectedContent, $tokens[$target]['content']);
|
||||
|
||||
}//end testDoubleQuotedString()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testDoubleQuotedString()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataDoubleQuotedString()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'testMarker' => '/* testSimple1 */',
|
||||
'expectedContent' => '"$foo"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testSimple2 */',
|
||||
'expectedContent' => '"{$foo}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testSimple3 */',
|
||||
'expectedContent' => '"${foo}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testDIM1 */',
|
||||
'expectedContent' => '"$foo[bar]"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testDIM2 */',
|
||||
'expectedContent' => '"{$foo[\'bar\']}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testDIM3 */',
|
||||
'expectedContent' => '"${foo[\'bar\']}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testProperty1 */',
|
||||
'expectedContent' => '"$foo->bar"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testProperty2 */',
|
||||
'expectedContent' => '"{$foo->bar}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testMethod1 */',
|
||||
'expectedContent' => '"{$foo->bar()}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testClosure1 */',
|
||||
'expectedContent' => '"{$foo()}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testChain1 */',
|
||||
'expectedContent' => '"{$foo[\'bar\']->baz()()}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testVariableVar1 */',
|
||||
'expectedContent' => '"${$bar}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testVariableVar2 */',
|
||||
'expectedContent' => '"${(foo)}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testVariableVar3 */',
|
||||
'expectedContent' => '"${foo->bar}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested1 */',
|
||||
'expectedContent' => '"${foo["${bar}"]}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested2 */',
|
||||
'expectedContent' => '"${foo["${bar[\'baz\']}"]}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested3 */',
|
||||
'expectedContent' => '"${foo->{$baz}}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested4 */',
|
||||
'expectedContent' => '"${foo->{${\'a\'}}}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested5 */',
|
||||
'expectedContent' => '"${foo->{"${\'a\'}"}}"',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testParseError */',
|
||||
'expectedContent' => '"${foo["${bar
|
||||
',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataDoubleQuotedString()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+95
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
enum Foo
|
||||
{
|
||||
/* testPureEnumCase */
|
||||
case SOME_CASE;
|
||||
}
|
||||
|
||||
enum Boo: int {
|
||||
/* testBackingIntegerEnumCase */
|
||||
case ONE = 1;
|
||||
}
|
||||
|
||||
enum Hoo: string
|
||||
{
|
||||
/* testBackingStringEnumCase */
|
||||
case ONE = 'one';
|
||||
}
|
||||
|
||||
enum ComplexEnum: int implements SomeInterface
|
||||
{
|
||||
use SomeTrait {
|
||||
traitMethod as enumMethod;
|
||||
}
|
||||
|
||||
const SOME_CONSTANT = true;
|
||||
|
||||
/* testEnumCaseInComplexEnum */
|
||||
case ONE = 1;
|
||||
|
||||
/* testEnumCaseIsCaseInsensitive */
|
||||
CaSe TWO = 2;
|
||||
|
||||
public function someMethod(): bool
|
||||
{
|
||||
switch (true) {
|
||||
/* testCaseWithSemicolonIsNotEnumCase */
|
||||
case CONSTANT;
|
||||
}
|
||||
}
|
||||
|
||||
/* testEnumCaseAfterSwitch */
|
||||
case THREE = 3;
|
||||
|
||||
public function someOtherMethod(): bool
|
||||
{
|
||||
switch (true):
|
||||
case false:
|
||||
endswitch;
|
||||
}
|
||||
|
||||
/* testEnumCaseAfterSwitchWithEndSwitch */
|
||||
case FOUR = 4;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
/* testCaseWithConstantIsNotEnumCase */
|
||||
case CONSTANT:
|
||||
/* testCaseWithConstantAndIdenticalIsNotEnumCase */
|
||||
case CONSTANT === 1:
|
||||
/* testCaseWithAssigmentToConstantIsNotEnumCase */
|
||||
case CONSTANT = 1:
|
||||
/* testIsNotEnumCaseIsCaseInsensitive */
|
||||
cAsE CONSTANT:
|
||||
}
|
||||
|
||||
switch ($x) {
|
||||
/* testCaseInSwitchWhenCreatingEnumInSwitch1 */
|
||||
case 'a': {
|
||||
enum Foo {}
|
||||
break;
|
||||
}
|
||||
|
||||
/* testCaseInSwitchWhenCreatingEnumInSwitch2 */
|
||||
case 'b';
|
||||
enum Bar {}
|
||||
break;
|
||||
}
|
||||
|
||||
enum Foo: string {
|
||||
/* testKeywordAsEnumCaseNameShouldBeString1 */
|
||||
case INTERFACE = 'interface';
|
||||
/* testKeywordAsEnumCaseNameShouldBeString2 */
|
||||
case TRAIT = 'trait';
|
||||
/* testKeywordAsEnumCaseNameShouldBeString3 */
|
||||
case ENUM = 'enum';
|
||||
/* testKeywordAsEnumCaseNameShouldBeString4 */
|
||||
case FUNCTION = 'function';
|
||||
/* testKeywordAsEnumCaseNameShouldBeString5 */
|
||||
case FALSE = 'false';
|
||||
/* testKeywordAsEnumCaseNameShouldBeString6 */
|
||||
case DEFAULT = 'default';
|
||||
/* testKeywordAsEnumCaseNameShouldBeString7 */
|
||||
case ARRAY = 'array';
|
||||
}
|
||||
Vendored
+157
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests converting enum "case" to T_ENUM_CASE.
|
||||
*
|
||||
* @author Jaroslav Hanslík <kukulich@kukulich.cz>
|
||||
* @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class EnumCaseTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that the enum "case" is converted to T_ENUM_CASE.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataEnumCases
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEnumCases($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$enumCase = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]);
|
||||
|
||||
$this->assertSame(T_ENUM_CASE, $tokens[$enumCase]['code']);
|
||||
$this->assertSame('T_ENUM_CASE', $tokens[$enumCase]['type']);
|
||||
|
||||
$this->assertArrayNotHasKey('scope_condition', $tokens[$enumCase], 'Scope condition is set');
|
||||
$this->assertArrayNotHasKey('scope_opener', $tokens[$enumCase], 'Scope opener is set');
|
||||
$this->assertArrayNotHasKey('scope_closer', $tokens[$enumCase], 'Scope closer is set');
|
||||
|
||||
}//end testEnumCases()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testEnumCases()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataEnumCases()
|
||||
{
|
||||
return [
|
||||
['/* testPureEnumCase */'],
|
||||
['/* testBackingIntegerEnumCase */'],
|
||||
['/* testBackingStringEnumCase */'],
|
||||
['/* testEnumCaseInComplexEnum */'],
|
||||
['/* testEnumCaseIsCaseInsensitive */'],
|
||||
['/* testEnumCaseAfterSwitch */'],
|
||||
['/* testEnumCaseAfterSwitchWithEndSwitch */'],
|
||||
];
|
||||
|
||||
}//end dataEnumCases()
|
||||
|
||||
|
||||
/**
|
||||
* Test that "case" that is not enum case is still tokenized as `T_CASE`.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataNotEnumCases
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotEnumCases($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$case = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]);
|
||||
|
||||
$this->assertSame(T_CASE, $tokens[$case]['code']);
|
||||
$this->assertSame('T_CASE', $tokens[$case]['type']);
|
||||
|
||||
$this->assertArrayHasKey('scope_condition', $tokens[$case], 'Scope condition is not set');
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$case], 'Scope opener is not set');
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$case], 'Scope closer is not set');
|
||||
|
||||
}//end testNotEnumCases()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNotEnumCases()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNotEnumCases()
|
||||
{
|
||||
return [
|
||||
['/* testCaseWithSemicolonIsNotEnumCase */'],
|
||||
['/* testCaseWithConstantIsNotEnumCase */'],
|
||||
['/* testCaseWithConstantAndIdenticalIsNotEnumCase */'],
|
||||
['/* testCaseWithAssigmentToConstantIsNotEnumCase */'],
|
||||
['/* testIsNotEnumCaseIsCaseInsensitive */'],
|
||||
['/* testCaseInSwitchWhenCreatingEnumInSwitch1 */'],
|
||||
['/* testCaseInSwitchWhenCreatingEnumInSwitch2 */'],
|
||||
];
|
||||
|
||||
}//end dataNotEnumCases()
|
||||
|
||||
|
||||
/**
|
||||
* Test that "case" that is not enum case is still tokenized as `T_CASE`.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataKeywordAsEnumCaseNameShouldBeString
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testKeywordAsEnumCaseNameShouldBeString($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$enumCaseName = $this->getTargetToken($testMarker, [T_STRING, T_INTERFACE, T_TRAIT, T_ENUM, T_FUNCTION, T_FALSE, T_DEFAULT, T_ARRAY]);
|
||||
|
||||
$this->assertSame(T_STRING, $tokens[$enumCaseName]['code']);
|
||||
$this->assertSame('T_STRING', $tokens[$enumCaseName]['type']);
|
||||
|
||||
}//end testKeywordAsEnumCaseNameShouldBeString()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testKeywordAsEnumCaseNameShouldBeString()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataKeywordAsEnumCaseNameShouldBeString()
|
||||
{
|
||||
return [
|
||||
['/* testKeywordAsEnumCaseNameShouldBeString1 */'],
|
||||
['/* testKeywordAsEnumCaseNameShouldBeString2 */'],
|
||||
['/* testKeywordAsEnumCaseNameShouldBeString3 */'],
|
||||
['/* testKeywordAsEnumCaseNameShouldBeString4 */'],
|
||||
];
|
||||
|
||||
}//end dataKeywordAsEnumCaseNameShouldBeString()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
try {
|
||||
// Do something.
|
||||
} catch(Exception $e) {
|
||||
// Do something.
|
||||
}
|
||||
/* testTryCatchFinally */
|
||||
finally {
|
||||
// Do something.
|
||||
}
|
||||
|
||||
/* testTryFinallyCatch */
|
||||
try {
|
||||
// Do something.
|
||||
} finally {
|
||||
// Do something.
|
||||
} catch(Exception $e) {
|
||||
// Do something.
|
||||
}
|
||||
|
||||
/* testTryFinally */
|
||||
try {
|
||||
// Do something.
|
||||
} FINALLY {
|
||||
// Do something.
|
||||
}
|
||||
|
||||
class FinallyAsMethod {
|
||||
/* testFinallyUsedAsClassConstantName */
|
||||
const FINALLY = 'foo';
|
||||
|
||||
/* testFinallyUsedAsMethodName */
|
||||
public function finally() {
|
||||
// Do something.
|
||||
|
||||
/* testFinallyUsedAsPropertyName */
|
||||
$this->finally = 'foo';
|
||||
}
|
||||
}
|
||||
Vendored
+96
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the tokenization of the finally keyword.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class FinallyTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that the finally keyword is tokenized as such.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataFinallyKeyword
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFinallyKeyword($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]);
|
||||
$this->assertSame(T_FINALLY, $tokens[$target]['code']);
|
||||
$this->assertSame('T_FINALLY', $tokens[$target]['type']);
|
||||
|
||||
}//end testFinallyKeyword()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testFinallyKeyword()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataFinallyKeyword()
|
||||
{
|
||||
return [
|
||||
['/* testTryCatchFinally */'],
|
||||
['/* testTryFinallyCatch */'],
|
||||
['/* testTryFinally */'],
|
||||
];
|
||||
|
||||
}//end dataFinallyKeyword()
|
||||
|
||||
|
||||
/**
|
||||
* Test that 'finally' when not used as the reserved keyword is tokenized as `T_STRING`.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataFinallyNonKeyword
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFinallyNonKeyword($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]);
|
||||
$this->assertSame(T_STRING, $tokens[$target]['code']);
|
||||
$this->assertSame('T_STRING', $tokens[$target]['type']);
|
||||
|
||||
}//end testFinallyNonKeyword()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testFinallyNonKeyword()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataFinallyNonKeyword()
|
||||
{
|
||||
return [
|
||||
['/* testFinallyUsedAsClassConstantName */'],
|
||||
['/* testFinallyUsedAsMethodName */'],
|
||||
['/* testFinallyUsedAsPropertyName */'],
|
||||
];
|
||||
|
||||
}//end dataFinallyNonKeyword()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+56
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/* testGotoStatement */
|
||||
goto marker;
|
||||
echo 'Foo';
|
||||
|
||||
/* testGotoDeclaration */
|
||||
marker:
|
||||
echo 'Bar';
|
||||
|
||||
/* testGotoStatementInLoop */
|
||||
for($i=0,$j=50; $i<100; $i++) {
|
||||
while($j--) {
|
||||
if($j==17) GOTO end;
|
||||
}
|
||||
}
|
||||
echo "i = $i";
|
||||
?>
|
||||
<div><?php $cond ? TEST_A : TEST_B ?></div>
|
||||
|
||||
<?php
|
||||
/* testGotoDeclarationOutsideLoop */
|
||||
end:
|
||||
echo 'j hit 17';
|
||||
|
||||
switch ($x) {
|
||||
/* testNotGotoDeclarationGlobalConstant */
|
||||
case CONSTANT:
|
||||
// Do something.
|
||||
break;
|
||||
|
||||
/* testNotGotoDeclarationNamespacedConstant */
|
||||
case MyNS\CONSTANT:
|
||||
// Do something.
|
||||
break;
|
||||
|
||||
/* testNotGotoDeclarationClassConstant */
|
||||
case MyClass::CONSTANT:
|
||||
// Do something.
|
||||
break;
|
||||
|
||||
/* testNotGotoDeclarationClassProperty */
|
||||
case $obj->property:
|
||||
// Do something.
|
||||
break;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
/* testNotGotoDeclarationGlobalConstantInTernary */
|
||||
case $x === ($cond) ? CONST_A : CONST_B:
|
||||
// Do something.
|
||||
break;
|
||||
}
|
||||
|
||||
/* testNotGotoDeclarationEnumWithType */
|
||||
enum Suit: string implements Colorful, CardGame {}
|
||||
Vendored
+175
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the tokenization of goto declarations and statements.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class GotoLabelTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the label in a goto statement is tokenized as T_STRING.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent The token content to expect.
|
||||
*
|
||||
* @dataProvider dataGotoStatement
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGotoStatement($testMarker, $testContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$label = $this->getTargetToken($testMarker, T_STRING);
|
||||
|
||||
$this->assertInternalType('int', $label);
|
||||
$this->assertSame($testContent, $tokens[$label]['content']);
|
||||
|
||||
}//end testGotoStatement()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testGotoStatement()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataGotoStatement()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testGotoStatement */',
|
||||
'marker',
|
||||
],
|
||||
[
|
||||
'/* testGotoStatementInLoop */',
|
||||
'end',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataGotoStatement()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the label in a goto declaration is tokenized as T_GOTO_LABEL.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent The token content to expect.
|
||||
*
|
||||
* @dataProvider dataGotoDeclaration
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGotoDeclaration($testMarker, $testContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$label = $this->getTargetToken($testMarker, T_GOTO_LABEL);
|
||||
|
||||
$this->assertInternalType('int', $label);
|
||||
$this->assertSame($testContent, $tokens[$label]['content']);
|
||||
|
||||
}//end testGotoDeclaration()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testGotoDeclaration()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataGotoDeclaration()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testGotoDeclaration */',
|
||||
'marker:',
|
||||
],
|
||||
[
|
||||
'/* testGotoDeclarationOutsideLoop */',
|
||||
'end:',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataGotoDeclaration()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the constant used in a switch - case statement is not confused with a goto label.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $testContent The token content to expect.
|
||||
*
|
||||
* @dataProvider dataNotAGotoDeclaration
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotAGotoDeclaration($testMarker, $testContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$target = $this->getTargetToken($testMarker, [T_GOTO_LABEL, T_STRING], $testContent);
|
||||
|
||||
$this->assertSame(T_STRING, $tokens[$target]['code']);
|
||||
$this->assertSame('T_STRING', $tokens[$target]['type']);
|
||||
|
||||
}//end testNotAGotoDeclaration()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNotAGotoDeclaration()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNotAGotoDeclaration()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testNotGotoDeclarationGlobalConstant */',
|
||||
'CONSTANT',
|
||||
],
|
||||
[
|
||||
'/* testNotGotoDeclarationNamespacedConstant */',
|
||||
'CONSTANT',
|
||||
],
|
||||
[
|
||||
'/* testNotGotoDeclarationClassConstant */',
|
||||
'CONSTANT',
|
||||
],
|
||||
[
|
||||
'/* testNotGotoDeclarationClassProperty */',
|
||||
'property',
|
||||
],
|
||||
[
|
||||
'/* testNotGotoDeclarationGlobalConstantInTernary */',
|
||||
'CONST_A',
|
||||
],
|
||||
[
|
||||
'/* testNotGotoDeclarationGlobalConstantInTernary */',
|
||||
'CONST_B',
|
||||
],
|
||||
[
|
||||
'/* testNotGotoDeclarationEnumWithType */',
|
||||
'Suit',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataNotAGotoDeclaration()
|
||||
|
||||
|
||||
}//end class
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/* testHeredocCloserNoIndent */
|
||||
$heredoc = <<<EOD
|
||||
some text
|
||||
some text
|
||||
some text
|
||||
EOD;
|
||||
|
||||
/* testNowdocCloserNoIndent */
|
||||
$nowdoc = <<<'EOD'
|
||||
some text
|
||||
some text
|
||||
some text
|
||||
EOD;
|
||||
|
||||
/* testHeredocCloserSpaceIndent */
|
||||
$heredoc = <<<END
|
||||
a
|
||||
b
|
||||
c
|
||||
END;
|
||||
|
||||
/* testNowdocCloserSpaceIndent */
|
||||
$nowdoc = <<<'END'
|
||||
a
|
||||
b
|
||||
c
|
||||
END;
|
||||
|
||||
/* testHeredocCloserTabIndent */
|
||||
$heredoc = <<<"END"
|
||||
a
|
||||
b
|
||||
c
|
||||
END;
|
||||
|
||||
/* testNowdocCloserTabIndent */
|
||||
$nowdoc = <<<'END'
|
||||
a
|
||||
b
|
||||
c
|
||||
END;
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the tokenization of goto declarations and statements.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Config;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Files\DummyFile;
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
/**
|
||||
* Heredoc/nowdoc closer token test.
|
||||
*
|
||||
* @requires PHP 7.3
|
||||
*/
|
||||
class HeredocNowdocCloserTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Initialize & tokenize \PHP_CodeSniffer\Files\File with code from the test case file.
|
||||
*
|
||||
* {@internal This is a near duplicate of the original method. Only difference is that
|
||||
* tab replacement is enabled for this test.}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
$config = new Config();
|
||||
$config->standards = ['PSR1'];
|
||||
$config->tabWidth = 4;
|
||||
|
||||
$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->process();
|
||||
|
||||
}//end setUpBeforeClass()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that leading (indent) whitespace in a heredoc/nowdoc closer token get the tab replacement treatment.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param array $expected Expectations for the token array.
|
||||
*
|
||||
* @dataProvider dataHeredocNowdocCloserTabReplacement
|
||||
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredocNowdocCloserTabReplacement($testMarker, $expected)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$closer = $this->getTargetToken($testMarker, [T_END_HEREDOC, T_END_NOWDOC]);
|
||||
|
||||
foreach ($expected as $key => $value) {
|
||||
if ($key === 'orig_content' && $value === null) {
|
||||
$this->assertArrayNotHasKey($key, $tokens[$closer], "Unexpected 'orig_content' key found in the token array.");
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey($key, $tokens[$closer], "Key $key not found in the token array.");
|
||||
$this->assertSame($value, $tokens[$closer][$key], "Value for key $key does not match expectation.");
|
||||
}
|
||||
|
||||
}//end testHeredocNowdocCloserTabReplacement()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testHeredocNowdocCloserTabReplacement()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataHeredocNowdocCloserTabReplacement()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'testMarker' => '/* testHeredocCloserNoIndent */',
|
||||
'expected' => [
|
||||
'length' => 3,
|
||||
'content' => 'EOD',
|
||||
'orig_content' => null,
|
||||
],
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNowdocCloserNoIndent */',
|
||||
'expected' => [
|
||||
'length' => 3,
|
||||
'content' => 'EOD',
|
||||
'orig_content' => null,
|
||||
],
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testHeredocCloserSpaceIndent */',
|
||||
'expected' => [
|
||||
'length' => 7,
|
||||
'content' => ' END',
|
||||
'orig_content' => null,
|
||||
],
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNowdocCloserSpaceIndent */',
|
||||
'expected' => [
|
||||
'length' => 8,
|
||||
'content' => ' END',
|
||||
'orig_content' => null,
|
||||
],
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testHeredocCloserTabIndent */',
|
||||
'expected' => [
|
||||
'length' => 8,
|
||||
'content' => ' END',
|
||||
'orig_content' => ' END',
|
||||
],
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNowdocCloserTabIndent */',
|
||||
'expected' => [
|
||||
'length' => 7,
|
||||
'content' => ' END',
|
||||
'orig_content' => ' END',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataHeredocNowdocCloserTabReplacement()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+193
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
// Test source: https://gist.github.com/iluuu1994/72e2154fc4150f2258316b0255b698f2#file-test-php
|
||||
|
||||
/* testSimple1 */
|
||||
$heredoc = <<<EOD
|
||||
$foo
|
||||
EOD;
|
||||
|
||||
/* testSimple2 */
|
||||
$heredoc = <<<"EOD"
|
||||
{$foo}
|
||||
EOD;
|
||||
|
||||
/* testSimple3 */
|
||||
$heredoc = <<<EOD
|
||||
${foo}
|
||||
EOD;
|
||||
|
||||
/* testDIM1 */
|
||||
$heredoc = <<<"EOD"
|
||||
$foo[bar]
|
||||
EOD;
|
||||
|
||||
/* testDIM2 */
|
||||
$heredoc = <<<EOD
|
||||
{$foo['bar']}
|
||||
EOD;
|
||||
|
||||
/* testDIM3 */
|
||||
$heredoc = <<<"EOD"
|
||||
${foo['bar']}
|
||||
EOD;
|
||||
|
||||
/* testProperty1 */
|
||||
$heredoc = <<<EOD
|
||||
$foo->bar
|
||||
EOD;
|
||||
|
||||
/* testProperty2 */
|
||||
$heredoc = <<<"EOD"
|
||||
{$foo->bar}
|
||||
EOD;
|
||||
|
||||
/* testMethod1 */
|
||||
$heredoc = <<<EOD
|
||||
{$foo->bar()}
|
||||
EOD;
|
||||
|
||||
/* testClosure1 */
|
||||
$heredoc = <<<"EOD"
|
||||
{$foo()}
|
||||
EOD;
|
||||
|
||||
/* testChain1 */
|
||||
$heredoc = <<<EOD
|
||||
{$foo['bar']->baz()()}
|
||||
EOD;
|
||||
|
||||
/* testVariableVar1 */
|
||||
$heredoc = <<<"EOD"
|
||||
${$bar}
|
||||
EOD;
|
||||
|
||||
/* testVariableVar2 */
|
||||
$heredoc = <<<EOD
|
||||
${(foo)}
|
||||
EOD;
|
||||
|
||||
/* testVariableVar3 */
|
||||
$heredoc = <<<"EOD"
|
||||
${foo->bar}
|
||||
EOD;
|
||||
|
||||
/* testNested1 */
|
||||
$heredoc = <<<EOD
|
||||
${foo["${bar}"]}
|
||||
EOD;
|
||||
|
||||
/* testNested2 */
|
||||
$heredoc = <<<"EOD"
|
||||
${foo["${bar['baz']}"]}
|
||||
EOD;
|
||||
|
||||
/* testNested3 */
|
||||
$heredoc = <<<EOD
|
||||
${foo->{$baz}}
|
||||
EOD;
|
||||
|
||||
/* testNested4 */
|
||||
$heredoc = <<<"EOD"
|
||||
${foo->{${'a'}}}
|
||||
EOD;
|
||||
|
||||
/* testNested5 */
|
||||
$heredoc = <<<EOD
|
||||
${foo->{"${'a'}"}}
|
||||
EOD;
|
||||
|
||||
/* testSimple1Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do $foo Something
|
||||
EOD;
|
||||
|
||||
/* testSimple2Wrapped */
|
||||
$heredoc = <<<"EOD"
|
||||
Do {$foo} Something
|
||||
EOD;
|
||||
|
||||
/* testSimple3Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do ${foo} Something
|
||||
EOD;
|
||||
|
||||
/* testDIM1Wrapped */
|
||||
$heredoc = <<<"EOD"
|
||||
Do $foo[bar] Something
|
||||
EOD;
|
||||
|
||||
/* testDIM2Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do {$foo['bar']} Something
|
||||
EOD;
|
||||
|
||||
/* testDIM3Wrapped */
|
||||
$heredoc = <<<"EOD"
|
||||
Do ${foo['bar']} Something
|
||||
EOD;
|
||||
|
||||
/* testProperty1Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do $foo->bar Something
|
||||
EOD;
|
||||
|
||||
/* testProperty2Wrapped */
|
||||
$heredoc = <<<"EOD"
|
||||
Do {$foo->bar} Something
|
||||
EOD;
|
||||
|
||||
/* testMethod1Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do {$foo->bar()} Something
|
||||
EOD;
|
||||
|
||||
/* testClosure1Wrapped */
|
||||
$heredoc = <<<"EOD"
|
||||
Do {$foo()} Something
|
||||
EOD;
|
||||
|
||||
/* testChain1Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do {$foo['bar']->baz()()} Something
|
||||
EOD;
|
||||
|
||||
/* testVariableVar1Wrapped */
|
||||
$heredoc = <<<"EOD"
|
||||
Do ${$bar} Something
|
||||
EOD;
|
||||
|
||||
/* testVariableVar2Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do ${(foo)} Something
|
||||
EOD;
|
||||
|
||||
/* testVariableVar3Wrapped */
|
||||
$heredoc = <<<"EOD"
|
||||
Do ${foo->bar} Something
|
||||
EOD;
|
||||
|
||||
/* testNested1Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do ${foo["${bar}"]} Something
|
||||
EOD;
|
||||
|
||||
/* testNested2Wrapped */
|
||||
$heredoc = <<<"EOD"
|
||||
Do ${foo["${bar['baz']}"]} Something
|
||||
EOD;
|
||||
|
||||
/* testNested3Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do ${foo->{$baz}} Something
|
||||
EOD;
|
||||
|
||||
/* testNested4Wrapped */
|
||||
$heredoc = <<<"EOD"
|
||||
Do ${foo->{${'a'}}} Something
|
||||
EOD;
|
||||
|
||||
/* testNested5Wrapped */
|
||||
$heredoc = <<<EOD
|
||||
Do ${foo->{"${'a'}"}} Something
|
||||
EOD;
|
||||
Vendored
+153
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests that embedded variables and expressions in heredoc strings are tokenized
|
||||
* as one heredoc string token.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class HeredocStringTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that heredoc strings contain the complete interpolated string.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param string $expectedContent The expected content of the heredoc string.
|
||||
*
|
||||
* @dataProvider dataHeredocString
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredocString($testMarker, $expectedContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$target = $this->getTargetToken($testMarker, T_HEREDOC);
|
||||
$this->assertSame($expectedContent."\n", $tokens[$target]['content']);
|
||||
|
||||
}//end testHeredocString()
|
||||
|
||||
|
||||
/**
|
||||
* Test that heredoc strings contain the complete interpolated string when combined with other texts.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param string $expectedContent The expected content of the heredoc string.
|
||||
*
|
||||
* @dataProvider dataHeredocString
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredocStringWrapped($testMarker, $expectedContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$testMarker = substr($testMarker, 0, -3).'Wrapped */';
|
||||
$target = $this->getTargetToken($testMarker, T_HEREDOC);
|
||||
$this->assertSame('Do '.$expectedContent." Something\n", $tokens[$target]['content']);
|
||||
|
||||
}//end testHeredocStringWrapped()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testHeredocString()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataHeredocString()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'testMarker' => '/* testSimple1 */',
|
||||
'expectedContent' => '$foo',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testSimple2 */',
|
||||
'expectedContent' => '{$foo}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testSimple3 */',
|
||||
'expectedContent' => '${foo}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testDIM1 */',
|
||||
'expectedContent' => '$foo[bar]',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testDIM2 */',
|
||||
'expectedContent' => '{$foo[\'bar\']}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testDIM3 */',
|
||||
'expectedContent' => '${foo[\'bar\']}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testProperty1 */',
|
||||
'expectedContent' => '$foo->bar',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testProperty2 */',
|
||||
'expectedContent' => '{$foo->bar}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testMethod1 */',
|
||||
'expectedContent' => '{$foo->bar()}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testClosure1 */',
|
||||
'expectedContent' => '{$foo()}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testChain1 */',
|
||||
'expectedContent' => '{$foo[\'bar\']->baz()()}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testVariableVar1 */',
|
||||
'expectedContent' => '${$bar}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testVariableVar2 */',
|
||||
'expectedContent' => '${(foo)}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testVariableVar3 */',
|
||||
'expectedContent' => '${foo->bar}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested1 */',
|
||||
'expectedContent' => '${foo["${bar}"]}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested2 */',
|
||||
'expectedContent' => '${foo["${bar[\'baz\']}"]}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested3 */',
|
||||
'expectedContent' => '${foo->{$baz}}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested4 */',
|
||||
'expectedContent' => '${foo->{${\'a\'}}}',
|
||||
],
|
||||
[
|
||||
'testMarker' => '/* testNested5 */',
|
||||
'expectedContent' => '${foo->{"${\'a\'}"}}',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataHeredocString()
|
||||
|
||||
|
||||
}//end class
|
||||
+407
@@ -0,0 +1,407 @@
|
||||
<?php
|
||||
|
||||
/* testPositionalArgs */
|
||||
array_fill(START_INDEX, \COUNT, MyNS\VALUE);
|
||||
|
||||
/* testNamedArgs */
|
||||
array_fill(start_index: 0, count: 100, value: 50);
|
||||
|
||||
/* testNamedArgsMultiline */
|
||||
array_fill(
|
||||
start_index : 0,
|
||||
count : 100,
|
||||
value : 50,
|
||||
);
|
||||
|
||||
/* testNamedArgsWithWhitespaceAndComments */
|
||||
array_fill ( start_index : 0, /*comment */ count /*comment*/ : 100, value: 50);
|
||||
|
||||
/* testMixedPositionalAndNamedArgs */
|
||||
htmlspecialchars($string, double_encode: false);
|
||||
|
||||
/* testNestedFunctionCallOuter */
|
||||
array_fill(
|
||||
start_index: $obj->getPos(skip: false),
|
||||
count: count(array_or_countable: $array),
|
||||
value: 50
|
||||
);
|
||||
|
||||
array_fill(
|
||||
start_index: /* testNestedFunctionCallInner1 */ $obj->getPos(skip: false),
|
||||
count: /* testNestedFunctionCallInner2 */ count(array_or_countable: $array),
|
||||
value: 50
|
||||
);
|
||||
|
||||
/* testNamespaceOperatorFunction */
|
||||
namespace\function_name(label:$string, more: false);
|
||||
|
||||
/* testNamespaceRelativeFunction */
|
||||
Partially\Qualified\function_name(label:$string, more: false);
|
||||
|
||||
/* testNamespacedFQNFunction */
|
||||
\Fully\Qualified\function_name(label: $string, more:false);
|
||||
|
||||
/* testVariableFunction */
|
||||
$fn(label: $string, more:false);
|
||||
|
||||
/* testVariableVariableFunction */
|
||||
${$fn}(label: $string, more:false);
|
||||
|
||||
/* testMethodCall */
|
||||
$obj->methodName(label: $foo, more: $bar);
|
||||
|
||||
/* testVariableMethodCall */
|
||||
$obj->{$var}(label: $foo, more: $bar);
|
||||
|
||||
/* testClassInstantiation */
|
||||
$obj = new MyClass(label: $string, more:false);
|
||||
|
||||
/* testClassInstantiationSelf */
|
||||
$obj = new self(label: $string, more:true);
|
||||
|
||||
/* testClassInstantiationStatic */
|
||||
$obj = new static(label: $string, more:false);
|
||||
|
||||
/* testAnonClass */
|
||||
$anon = new class(label: $string, more: false) {
|
||||
public function __construct($label, $more) {}
|
||||
};
|
||||
|
||||
function myfoo( $💩💩💩, $Пасха, $_valid) {}
|
||||
/* testNonAsciiNames */
|
||||
foo(💩💩💩: [], Пасха: 'text', _valid: 123);
|
||||
|
||||
/* testMixedPositionalAndNamedArgsWithTernary */
|
||||
foo( $cond ? true : false, name: $value2 );
|
||||
|
||||
/* testNamedArgWithTernary */
|
||||
foo( label: $cond ? true : false, more: $cond ? CONSTANT_A : CONSTANT_B );
|
||||
|
||||
/* testTernaryWithFunctionCallsInThenElse */
|
||||
echo $cond ? foo( label: $something ) : foo( more: $something_else );
|
||||
|
||||
/* testTernaryWithConstantsInThenElse */
|
||||
echo $cond ? CONSTANT_NAME : OTHER_CONSTANT;
|
||||
|
||||
switch ($s) {
|
||||
/* testSwitchCaseWithConstant */
|
||||
case MY_CONSTANT:
|
||||
// Do something.
|
||||
break;
|
||||
|
||||
/* testSwitchCaseWithClassProperty */
|
||||
case $obj->property:
|
||||
// Do something.
|
||||
break;
|
||||
|
||||
/* testSwitchDefault */
|
||||
default:
|
||||
// Do something.
|
||||
break;
|
||||
}
|
||||
|
||||
/* testTernaryWithClosuresAndReturnTypes */
|
||||
$closure = $cond ? function() : bool {return true;} : function() : int {return 123;};
|
||||
|
||||
/* testTernaryWithArrowFunctionsAndReturnTypes */
|
||||
$fn = $cond ? fn() : bool => true : fn() : int => 123;
|
||||
|
||||
|
||||
/* testCompileErrorNamedBeforePositional */
|
||||
// Not the concern of PHPCS. Should still be handled.
|
||||
test(param: $bar, $foo);
|
||||
|
||||
/* testDuplicateName1 */
|
||||
// Error Exception, but not the concern of PHPCS. Should still be handled.
|
||||
test(param: 1, /* testDuplicateName2 */ param: 2);
|
||||
|
||||
/* testIncorrectOrderWithVariadic */
|
||||
// Error Exception, but not the concern of PHPCS. Should still be handled.
|
||||
array_fill(start_index: 0, ...[100, 50]);
|
||||
|
||||
/* testCompileErrorIncorrectOrderWithVariadic */
|
||||
// Not the concern of PHPCS. Should still be handled.
|
||||
test(...$values, param: $value); // Compile-time error
|
||||
|
||||
/* testParseErrorNoValue */
|
||||
// Not the concern of PHPCS. Should still be handled.
|
||||
test(param1:, param2:);
|
||||
|
||||
/* testParseErrorDynamicName */
|
||||
// Parse error. Ignore.
|
||||
function_name($variableStoringParamName: $value);
|
||||
|
||||
/* testParseErrorExit */
|
||||
// Exit is a language construct, not a function. Named params not supported, handle it anyway.
|
||||
exit(status: $value);
|
||||
|
||||
/* testParseErrorEmpty */
|
||||
// Empty is a language construct, not a function. Named params not supported, handle it anyway.
|
||||
empty(variable: $value);
|
||||
|
||||
/* testParseErrorEval */
|
||||
// Eval is a language construct, not a function. Named params not supported, handle it anyway.
|
||||
eval(code: $value);
|
||||
|
||||
/* testParseErrorArbitraryParentheses */
|
||||
// Parse error. Not named param, handle it anyway.
|
||||
$calc = (something: $value / $other);
|
||||
|
||||
|
||||
/* testReservedKeywordAbstract1 */
|
||||
foobar(abstract: $value, /* testReservedKeywordAbstract2 */ abstract: $value);
|
||||
|
||||
/* testReservedKeywordAnd1 */
|
||||
foobar(and: $value, /* testReservedKeywordAnd2 */ and: $value);
|
||||
|
||||
/* testReservedKeywordArray1 */
|
||||
foobar(array: $value, /* testReservedKeywordArray2 */ array: $value);
|
||||
|
||||
/* testReservedKeywordAs1 */
|
||||
foobar(as: $value, /* testReservedKeywordAs2 */ as: $value);
|
||||
|
||||
/* testReservedKeywordBreak1 */
|
||||
foobar(break: $value, /* testReservedKeywordBreak2 */ break: $value);
|
||||
|
||||
/* testReservedKeywordCallable1 */
|
||||
foobar(callable: $value, /* testReservedKeywordCallable2 */ callable: $value);
|
||||
|
||||
/* testReservedKeywordCase1 */
|
||||
foobar(case: $value, /* testReservedKeywordCase2 */ case: $value);
|
||||
|
||||
/* testReservedKeywordCatch1 */
|
||||
foobar(catch: $value, /* testReservedKeywordCatch2 */ catch: $value);
|
||||
|
||||
/* testReservedKeywordClass1 */
|
||||
foobar(class: $value, /* testReservedKeywordClass2 */ class: $value);
|
||||
|
||||
/* testReservedKeywordClone1 */
|
||||
foobar(clone: $value, /* testReservedKeywordClone2 */ clone: $value);
|
||||
|
||||
/* testReservedKeywordConst1 */
|
||||
foobar(const: $value, /* testReservedKeywordConst2 */ const: $value);
|
||||
|
||||
/* testReservedKeywordContinue1 */
|
||||
foobar(continue: $value, /* testReservedKeywordContinue2 */ continue: $value);
|
||||
|
||||
/* testReservedKeywordDeclare1 */
|
||||
foobar(declare: $value, /* testReservedKeywordDeclare2 */ declare: $value);
|
||||
|
||||
/* testReservedKeywordDefault1 */
|
||||
foobar(default: $value, /* testReservedKeywordDefault2 */ default: $value);
|
||||
|
||||
/* testReservedKeywordDie1 */
|
||||
foobar(die: $value, /* testReservedKeywordDie2 */ die: $value);
|
||||
|
||||
/* testReservedKeywordDo1 */
|
||||
foobar(do: $value, /* testReservedKeywordDo2 */ do: $value);
|
||||
|
||||
/* testReservedKeywordEcho1 */
|
||||
foobar(echo: $value, /* testReservedKeywordEcho2 */ echo: $value);
|
||||
|
||||
/* testReservedKeywordElse1 */
|
||||
foobar(else: $value, /* testReservedKeywordElse2 */ else: $value);
|
||||
|
||||
/* testReservedKeywordElseif1 */
|
||||
foobar(elseif: $value, /* testReservedKeywordElseif2 */ elseif: $value);
|
||||
|
||||
/* testReservedKeywordEmpty1 */
|
||||
foobar(empty: $value, /* testReservedKeywordEmpty2 */ empty: $value);
|
||||
|
||||
/* testReservedKeywordEnum1 */
|
||||
foobar(enum: $value, /* testReservedKeywordEnum2 */ enum: $value);
|
||||
|
||||
/* testReservedKeywordEnddeclare1 */
|
||||
foobar(enddeclare: $value, /* testReservedKeywordEnddeclare2 */ enddeclare: $value);
|
||||
|
||||
/* testReservedKeywordEndfor1 */
|
||||
foobar(endfor: $value, /* testReservedKeywordEndfor2 */ endfor: $value);
|
||||
|
||||
/* testReservedKeywordEndforeach1 */
|
||||
foobar(endforeach: $value, /* testReservedKeywordEndforeach2 */ endforeach: $value);
|
||||
|
||||
/* testReservedKeywordEndif1 */
|
||||
foobar(endif: $value, /* testReservedKeywordEndif2 */ endif: $value);
|
||||
|
||||
/* testReservedKeywordEndswitch1 */
|
||||
foobar(endswitch: $value, /* testReservedKeywordEndswitch2 */ endswitch: $value);
|
||||
|
||||
/* testReservedKeywordEndwhile1 */
|
||||
foobar(endwhile: $value, /* testReservedKeywordEndwhile2 */ endwhile: $value);
|
||||
|
||||
/* testReservedKeywordEval1 */
|
||||
foobar(eval: $value, /* testReservedKeywordEval2 */ eval: $value);
|
||||
|
||||
/* testReservedKeywordExit1 */
|
||||
foobar(exit: $value, /* testReservedKeywordExit2 */ exit: $value);
|
||||
|
||||
/* testReservedKeywordExtends1 */
|
||||
foobar(extends: $value, /* testReservedKeywordExtends2 */ extends: $value);
|
||||
|
||||
/* testReservedKeywordFinal1 */
|
||||
foobar(final: $value, /* testReservedKeywordFinal2 */ final: $value);
|
||||
|
||||
/* testReservedKeywordFinally1 */
|
||||
foobar(finally: $value, /* testReservedKeywordFinally2 */ finally: $value);
|
||||
|
||||
/* testReservedKeywordFn1 */
|
||||
foobar(fn: $value, /* testReservedKeywordFn2 */ fn: $value);
|
||||
|
||||
/* testReservedKeywordFor1 */
|
||||
foobar(for: $value, /* testReservedKeywordFor2 */ for: $value);
|
||||
|
||||
/* testReservedKeywordForeach1 */
|
||||
foobar(foreach: $value, /* testReservedKeywordForeach2 */ foreach: $value);
|
||||
|
||||
/* testReservedKeywordFunction1 */
|
||||
foobar(function: $value, /* testReservedKeywordFunction2 */ function: $value);
|
||||
|
||||
/* testReservedKeywordGlobal1 */
|
||||
foobar(global: $value, /* testReservedKeywordGlobal2 */ global: $value);
|
||||
|
||||
/* testReservedKeywordGoto1 */
|
||||
foobar(goto: $value, /* testReservedKeywordGoto2 */ goto: $value);
|
||||
|
||||
/* testReservedKeywordIf1 */
|
||||
foobar(if: $value, /* testReservedKeywordIf2 */ if: $value);
|
||||
|
||||
/* testReservedKeywordImplements1 */
|
||||
foobar(implements: $value, /* testReservedKeywordImplements2 */ implements: $value);
|
||||
|
||||
/* testReservedKeywordInclude1 */
|
||||
foobar(include: $value, /* testReservedKeywordInclude2 */ include: $value);
|
||||
|
||||
/* testReservedKeywordInclude_once1 */
|
||||
foobar(include_once: $value, /* testReservedKeywordInclude_once2 */ include_once: $value);
|
||||
|
||||
/* testReservedKeywordInstanceof1 */
|
||||
foobar(instanceof: $value, /* testReservedKeywordInstanceof2 */ instanceof: $value);
|
||||
|
||||
/* testReservedKeywordInsteadof1 */
|
||||
foobar(insteadof: $value, /* testReservedKeywordInsteadof2 */ insteadof: $value);
|
||||
|
||||
/* testReservedKeywordInterface1 */
|
||||
foobar(interface: $value, /* testReservedKeywordInterface2 */ interface: $value);
|
||||
|
||||
/* testReservedKeywordIsset1 */
|
||||
foobar(isset: $value, /* testReservedKeywordIsset2 */ isset: $value);
|
||||
|
||||
/* testReservedKeywordList1 */
|
||||
foobar(list: $value, /* testReservedKeywordList2 */ list: $value);
|
||||
|
||||
/* testReservedKeywordMatch1 */
|
||||
foobar(match: $value, /* testReservedKeywordMatch2 */ match: $value);
|
||||
|
||||
/* testReservedKeywordNamespace1 */
|
||||
foobar(namespace: $value, /* testReservedKeywordNamespace2 */ namespace: $value);
|
||||
|
||||
/* testReservedKeywordNew1 */
|
||||
foobar(new: $value, /* testReservedKeywordNew2 */ new: $value);
|
||||
|
||||
/* testReservedKeywordOr1 */
|
||||
foobar(or: $value, /* testReservedKeywordOr2 */ or: $value);
|
||||
|
||||
/* testReservedKeywordPrint1 */
|
||||
foobar(print: $value, /* testReservedKeywordPrint2 */ print: $value);
|
||||
|
||||
/* testReservedKeywordPrivate1 */
|
||||
foobar(private: $value, /* testReservedKeywordPrivate2 */ private: $value);
|
||||
|
||||
/* testReservedKeywordProtected1 */
|
||||
foobar(protected: $value, /* testReservedKeywordProtected2 */ protected: $value);
|
||||
|
||||
/* testReservedKeywordPublic1 */
|
||||
foobar(public: $value, /* testReservedKeywordPublic2 */ public: $value);
|
||||
|
||||
/* testReservedKeywordReadonly1 */
|
||||
foobar(readonly: $value, /* testReservedKeywordReadonly2 */ readonly: $value);
|
||||
|
||||
/* testReservedKeywordRequire1 */
|
||||
foobar(require: $value, /* testReservedKeywordRequire2 */ require: $value);
|
||||
|
||||
/* testReservedKeywordRequire_once1 */
|
||||
foobar(require_once: $value, /* testReservedKeywordRequire_once2 */ require_once: $value);
|
||||
|
||||
/* testReservedKeywordReturn1 */
|
||||
foobar(return: $value, /* testReservedKeywordReturn2 */ return: $value);
|
||||
|
||||
/* testReservedKeywordStatic1 */
|
||||
foobar(static: $value, /* testReservedKeywordStatic2 */ static: $value);
|
||||
|
||||
/* testReservedKeywordSwitch1 */
|
||||
foobar(switch: $value, /* testReservedKeywordSwitch2 */ switch: $value);
|
||||
|
||||
/* testReservedKeywordThrow1 */
|
||||
foobar(throw: $value, /* testReservedKeywordThrow2 */ throw: $value);
|
||||
|
||||
/* testReservedKeywordTrait1 */
|
||||
foobar(trait: $value, /* testReservedKeywordTrait2 */ trait: $value);
|
||||
|
||||
/* testReservedKeywordTry1 */
|
||||
foobar(try: $value, /* testReservedKeywordTry2 */ try: $value);
|
||||
|
||||
/* testReservedKeywordUnset1 */
|
||||
foobar(unset: $value, /* testReservedKeywordUnset2 */ unset: $value);
|
||||
|
||||
/* testReservedKeywordUse1 */
|
||||
foobar(use: $value, /* testReservedKeywordUse2 */ use: $value);
|
||||
|
||||
/* testReservedKeywordVar1 */
|
||||
foobar(var: $value, /* testReservedKeywordVar2 */ var: $value);
|
||||
|
||||
/* testReservedKeywordWhile1 */
|
||||
foobar(while: $value, /* testReservedKeywordWhile2 */ while: $value);
|
||||
|
||||
/* testReservedKeywordXor1 */
|
||||
foobar(xor: $value, /* testReservedKeywordXor2 */ xor: $value);
|
||||
|
||||
/* testReservedKeywordYield1 */
|
||||
foobar(yield: $value, /* testReservedKeywordYield2 */ yield: $value);
|
||||
|
||||
/* testReservedKeywordInt1 */
|
||||
foobar(int: $value, /* testReservedKeywordInt2 */ int: $value);
|
||||
|
||||
/* testReservedKeywordFloat1 */
|
||||
foobar(float: $value, /* testReservedKeywordFloat2 */ float: $value);
|
||||
|
||||
/* testReservedKeywordBool1 */
|
||||
foobar(bool: $value, /* testReservedKeywordBool2 */ bool: $value);
|
||||
|
||||
/* testReservedKeywordString1 */
|
||||
foobar(string: $value, /* testReservedKeywordString2 */ string: $value);
|
||||
|
||||
/* testReservedKeywordTrue1 */
|
||||
foobar(true: $value, /* testReservedKeywordTrue2 */ true: $value);
|
||||
|
||||
/* testReservedKeywordFalse1 */
|
||||
foobar(false: $value, /* testReservedKeywordFalse2 */ false: $value);
|
||||
|
||||
/* testReservedKeywordNull1 */
|
||||
foobar(null: $value, /* testReservedKeywordNull2 */ null: $value);
|
||||
|
||||
/* testReservedKeywordVoid1 */
|
||||
foobar(void: $value, /* testReservedKeywordVoid2 */ void: $value);
|
||||
|
||||
/* testReservedKeywordIterable1 */
|
||||
foobar(iterable: $value, /* testReservedKeywordIterable2 */ iterable: $value);
|
||||
|
||||
/* testReservedKeywordObject1 */
|
||||
foobar(object: $value, /* testReservedKeywordObject2 */ object: $value);
|
||||
|
||||
/* testReservedKeywordResource1 */
|
||||
foobar(resource: $value, /* testReservedKeywordResource2 */ resource: $value);
|
||||
|
||||
/* testReservedKeywordMixed1 */
|
||||
foobar(mixed: $value, /* testReservedKeywordMixed2 */ mixed: $value);
|
||||
|
||||
/* testReservedKeywordNumeric1 */
|
||||
foobar(numeric: $value, /* testReservedKeywordNumeric2 */ numeric: $value);
|
||||
|
||||
/* testReservedKeywordParent1 */
|
||||
foobar(parent: $value, /* testReservedKeywordParent2 */ parent: $value);
|
||||
|
||||
/* testReservedKeywordSelf1 */
|
||||
foobar(self: $value, /* testReservedKeywordSelf2 */ self: $value);
|
||||
|
||||
/* testReservedKeywordNever1 */
|
||||
foobar(never: $value, /* testReservedKeywordNever2 */ never: $value);
|
||||
+885
@@ -0,0 +1,885 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the backfilling of the T_FN token to PHP < 7.4.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
|
||||
class NamedFunctionCallArgumentsTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Verify that parameter labels are tokenized as T_PARAM_NAME and that
|
||||
* the colon after it is tokenized as a T_COLON.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param array $parameters The token content for each parameter label to look for.
|
||||
*
|
||||
* @dataProvider dataNamedFunctionCallArguments
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNamedFunctionCallArguments($testMarker, $parameters)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
foreach ($parameters as $content) {
|
||||
$label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content);
|
||||
|
||||
$this->assertSame(
|
||||
T_PARAM_NAME,
|
||||
$tokens[$label]['code'],
|
||||
'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_PARAM_NAME',
|
||||
$tokens[$label]['type'],
|
||||
'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (type)'
|
||||
);
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
':',
|
||||
$tokens[$colon]['content'],
|
||||
'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content']
|
||||
);
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
}//end foreach
|
||||
|
||||
}//end testNamedFunctionCallArguments()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNamedFunctionCallArguments()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNamedFunctionCallArguments()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testNamedArgs */',
|
||||
[
|
||||
'start_index',
|
||||
'count',
|
||||
'value',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNamedArgsMultiline */',
|
||||
[
|
||||
'start_index',
|
||||
'count',
|
||||
'value',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNamedArgsWithWhitespaceAndComments */',
|
||||
[
|
||||
'start_index',
|
||||
'count',
|
||||
'value',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMixedPositionalAndNamedArgs */',
|
||||
['double_encode'],
|
||||
],
|
||||
[
|
||||
'/* testNestedFunctionCallOuter */',
|
||||
[
|
||||
'start_index',
|
||||
'count',
|
||||
'value',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNestedFunctionCallInner1 */',
|
||||
['skip'],
|
||||
],
|
||||
[
|
||||
'/* testNestedFunctionCallInner2 */',
|
||||
['array_or_countable'],
|
||||
],
|
||||
[
|
||||
'/* testNamespaceOperatorFunction */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNamespaceRelativeFunction */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNamespacedFQNFunction */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testVariableFunction */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testVariableVariableFunction */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMethodCall */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testVariableMethodCall */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testClassInstantiation */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testClassInstantiationSelf */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testClassInstantiationStatic */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testAnonClass */',
|
||||
[
|
||||
'label',
|
||||
'more',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNonAsciiNames */',
|
||||
[
|
||||
'💩💩💩',
|
||||
'Пасха',
|
||||
'_valid',
|
||||
],
|
||||
],
|
||||
|
||||
// Coding errors which should still be handled.
|
||||
[
|
||||
'/* testCompileErrorNamedBeforePositional */',
|
||||
['param'],
|
||||
],
|
||||
[
|
||||
'/* testDuplicateName1 */',
|
||||
['param'],
|
||||
],
|
||||
[
|
||||
'/* testDuplicateName2 */',
|
||||
['param'],
|
||||
],
|
||||
[
|
||||
'/* testIncorrectOrderWithVariadic */',
|
||||
['start_index'],
|
||||
],
|
||||
[
|
||||
'/* testCompileErrorIncorrectOrderWithVariadic */',
|
||||
['param'],
|
||||
],
|
||||
[
|
||||
'/* testParseErrorNoValue */',
|
||||
[
|
||||
'param1',
|
||||
'param2',
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testParseErrorExit */',
|
||||
['status'],
|
||||
],
|
||||
[
|
||||
'/* testParseErrorEmpty */',
|
||||
['variable'],
|
||||
],
|
||||
[
|
||||
'/* testParseErrorEval */',
|
||||
['code'],
|
||||
],
|
||||
[
|
||||
'/* testParseErrorArbitraryParentheses */',
|
||||
['something'],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataNamedFunctionCallArguments()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that other T_STRING tokens within a function call are still tokenized as T_STRING.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param string $content The token content to look for.
|
||||
*
|
||||
* @dataProvider dataOtherTstringInFunctionCall
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testOtherTstringInFunctionCall($testMarker, $content)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content);
|
||||
|
||||
$this->assertSame(
|
||||
T_STRING,
|
||||
$tokens[$label]['code'],
|
||||
'Token tokenized as '.$tokens[$label]['type'].', not T_STRING (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_STRING',
|
||||
$tokens[$label]['type'],
|
||||
'Token tokenized as '.$tokens[$label]['type'].', not T_STRING (type)'
|
||||
);
|
||||
|
||||
}//end testOtherTstringInFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testOtherTstringInFunctionCall()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataOtherTstringInFunctionCall()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testPositionalArgs */',
|
||||
'START_INDEX',
|
||||
],
|
||||
[
|
||||
'/* testPositionalArgs */',
|
||||
'COUNT',
|
||||
],
|
||||
[
|
||||
'/* testPositionalArgs */',
|
||||
'VALUE',
|
||||
],
|
||||
[
|
||||
'/* testNestedFunctionCallInner2 */',
|
||||
'count',
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataOtherTstringInFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Verify whether the colons are tokenized correctly when a ternary is used in a mixed
|
||||
* positional and named arguments function call.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMixedPositionalAndNamedArgsWithTernary()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$true = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_TRUE);
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
T_INLINE_ELSE,
|
||||
$tokens[$colon]['code'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_INLINE_ELSE',
|
||||
$tokens[$colon]['type'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)'
|
||||
);
|
||||
|
||||
$label = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_PARAM_NAME, 'name');
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
':',
|
||||
$tokens[$colon]['content'],
|
||||
'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content']
|
||||
);
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
}//end testMixedPositionalAndNamedArgsWithTernary()
|
||||
|
||||
|
||||
/**
|
||||
* Verify whether the colons are tokenized correctly when a ternary is used
|
||||
* in a named arguments function call.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNamedArgWithTernary()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
/*
|
||||
* First argument.
|
||||
*/
|
||||
|
||||
$label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'label');
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
':',
|
||||
$tokens[$colon]['content'],
|
||||
'First arg: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content']
|
||||
);
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'First arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'First arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
$true = $this->getTargetToken('/* testNamedArgWithTernary */', T_TRUE);
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
T_INLINE_ELSE,
|
||||
$tokens[$colon]['code'],
|
||||
'First arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_INLINE_ELSE',
|
||||
$tokens[$colon]['type'],
|
||||
'First arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)'
|
||||
);
|
||||
|
||||
/*
|
||||
* Second argument.
|
||||
*/
|
||||
|
||||
$label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'more');
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
':',
|
||||
$tokens[$colon]['content'],
|
||||
'Second arg: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content']
|
||||
);
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'Second arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'Second arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
$true = $this->getTargetToken('/* testNamedArgWithTernary */', T_STRING, 'CONSTANT_A');
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
T_INLINE_ELSE,
|
||||
$tokens[$colon]['code'],
|
||||
'Second arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_INLINE_ELSE',
|
||||
$tokens[$colon]['type'],
|
||||
'Second arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)'
|
||||
);
|
||||
|
||||
}//end testNamedArgWithTernary()
|
||||
|
||||
|
||||
/**
|
||||
* Verify whether the colons are tokenized correctly when named arguments
|
||||
* function calls are used in a ternary.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTernaryWithFunctionCallsInThenElse()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
/*
|
||||
* Then.
|
||||
*/
|
||||
|
||||
$label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'label');
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
':',
|
||||
$tokens[$colon]['content'],
|
||||
'Function in then: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content']
|
||||
);
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'Function in then: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'Function in then: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
$closeParens = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_CLOSE_PARENTHESIS);
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($closeParens + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
T_INLINE_ELSE,
|
||||
$tokens[$colon]['code'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_INLINE_ELSE',
|
||||
$tokens[$colon]['type'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)'
|
||||
);
|
||||
|
||||
/*
|
||||
* Else.
|
||||
*/
|
||||
|
||||
$label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'more');
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
':',
|
||||
$tokens[$colon]['content'],
|
||||
'Function in else: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content']
|
||||
);
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'Function in else: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'Function in else: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
}//end testTernaryWithFunctionCallsInThenElse()
|
||||
|
||||
|
||||
/**
|
||||
* Verify whether the colons are tokenized correctly when constants are used in a ternary.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTernaryWithConstantsInThenElse()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$constant = $this->getTargetToken('/* testTernaryWithConstantsInThenElse */', T_STRING, 'CONSTANT_NAME');
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($constant + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
T_INLINE_ELSE,
|
||||
$tokens[$colon]['code'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_INLINE_ELSE',
|
||||
$tokens[$colon]['type'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)'
|
||||
);
|
||||
|
||||
}//end testTernaryWithConstantsInThenElse()
|
||||
|
||||
|
||||
/**
|
||||
* Verify whether the colons are tokenized correctly in a switch statement.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSwitchStatement()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$label = $this->getTargetToken('/* testSwitchCaseWithConstant */', T_STRING, 'MY_CONSTANT');
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'First case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'First case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
$label = $this->getTargetToken('/* testSwitchCaseWithClassProperty */', T_STRING, 'property');
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'Second case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'Second case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
$default = $this->getTargetToken('/* testSwitchDefault */', T_DEFAULT);
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($default + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'Default case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'Default case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
}//end testSwitchStatement()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that a variable parameter label (parse error) is still tokenized as T_VARIABLE.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testParseErrorVariableLabel()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$label = $this->getTargetToken('/* testParseErrorDynamicName */', [T_VARIABLE, T_PARAM_NAME], '$variableStoringParamName');
|
||||
|
||||
$this->assertSame(
|
||||
T_VARIABLE,
|
||||
$tokens[$label]['code'],
|
||||
'Token tokenized as '.$tokens[$label]['type'].', not T_VARIABLE (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_VARIABLE',
|
||||
$tokens[$label]['type'],
|
||||
'Token tokenized as '.$tokens[$label]['type'].', not T_VARIABLE (type)'
|
||||
);
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
':',
|
||||
$tokens[$colon]['content'],
|
||||
'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content']
|
||||
);
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
}//end testParseErrorVariableLabel()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that reserved keywords used as a parameter label are tokenized as T_PARAM_NAME
|
||||
* and that the colon after it is tokenized as a T_COLON.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the target token.
|
||||
* @param array $tokenTypes The token codes to look for.
|
||||
* @param string $tokenContent The token content to look for.
|
||||
*
|
||||
* @dataProvider dataReservedKeywordsAsName
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReservedKeywordsAsName($testMarker, $tokenTypes, $tokenContent)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$label = $this->getTargetToken($testMarker, $tokenTypes, $tokenContent);
|
||||
|
||||
$this->assertSame(
|
||||
T_PARAM_NAME,
|
||||
$tokens[$label]['code'],
|
||||
'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_PARAM_NAME',
|
||||
$tokens[$label]['type'],
|
||||
'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (type)'
|
||||
);
|
||||
|
||||
// Get the next non-empty token.
|
||||
$colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
|
||||
|
||||
$this->assertSame(
|
||||
':',
|
||||
$tokens[$colon]['content'],
|
||||
'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content']
|
||||
);
|
||||
$this->assertSame(
|
||||
T_COLON,
|
||||
$tokens[$colon]['code'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)'
|
||||
);
|
||||
$this->assertSame(
|
||||
'T_COLON',
|
||||
$tokens[$colon]['type'],
|
||||
'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)'
|
||||
);
|
||||
|
||||
}//end testReservedKeywordsAsName()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testReservedKeywordsAsName()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataReservedKeywordsAsName()
|
||||
{
|
||||
$reservedKeywords = [
|
||||
// '__halt_compiler', NOT TESTABLE
|
||||
'abstract',
|
||||
'and',
|
||||
'array',
|
||||
'as',
|
||||
'break',
|
||||
'callable',
|
||||
'case',
|
||||
'catch',
|
||||
'class',
|
||||
'clone',
|
||||
'const',
|
||||
'continue',
|
||||
'declare',
|
||||
'default',
|
||||
'die',
|
||||
'do',
|
||||
'echo',
|
||||
'else',
|
||||
'elseif',
|
||||
'empty',
|
||||
'enddeclare',
|
||||
'endfor',
|
||||
'endforeach',
|
||||
'endif',
|
||||
'endswitch',
|
||||
'endwhile',
|
||||
'enum',
|
||||
'eval',
|
||||
'exit',
|
||||
'extends',
|
||||
'final',
|
||||
'finally',
|
||||
'fn',
|
||||
'for',
|
||||
'foreach',
|
||||
'function',
|
||||
'global',
|
||||
'goto',
|
||||
'if',
|
||||
'implements',
|
||||
'include',
|
||||
'include_once',
|
||||
'instanceof',
|
||||
'insteadof',
|
||||
'interface',
|
||||
'isset',
|
||||
'list',
|
||||
'match',
|
||||
'namespace',
|
||||
'new',
|
||||
'or',
|
||||
'print',
|
||||
'private',
|
||||
'protected',
|
||||
'public',
|
||||
'readonly',
|
||||
'require',
|
||||
'require_once',
|
||||
'return',
|
||||
'static',
|
||||
'switch',
|
||||
'throw',
|
||||
'trait',
|
||||
'try',
|
||||
'unset',
|
||||
'use',
|
||||
'var',
|
||||
'while',
|
||||
'xor',
|
||||
'yield',
|
||||
'int',
|
||||
'float',
|
||||
'bool',
|
||||
'string',
|
||||
'true',
|
||||
'false',
|
||||
'null',
|
||||
'void',
|
||||
'iterable',
|
||||
'object',
|
||||
'resource',
|
||||
'mixed',
|
||||
'numeric',
|
||||
'never',
|
||||
|
||||
// Not reserved keyword, but do have their own token in PHPCS.
|
||||
'parent',
|
||||
'self',
|
||||
];
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($reservedKeywords as $keyword) {
|
||||
$tokensTypes = [
|
||||
T_PARAM_NAME,
|
||||
T_STRING,
|
||||
T_GOTO_LABEL,
|
||||
];
|
||||
$tokenName = 'T_'.strtoupper($keyword);
|
||||
|
||||
if ($keyword === 'and') {
|
||||
$tokensTypes[] = T_LOGICAL_AND;
|
||||
} else if ($keyword === 'die') {
|
||||
$tokensTypes[] = T_EXIT;
|
||||
} else if ($keyword === 'or') {
|
||||
$tokensTypes[] = T_LOGICAL_OR;
|
||||
} else if ($keyword === 'xor') {
|
||||
$tokensTypes[] = T_LOGICAL_XOR;
|
||||
} else if ($keyword === '__halt_compiler') {
|
||||
$tokensTypes[] = T_HALT_COMPILER;
|
||||
} else if (defined($tokenName) === true) {
|
||||
$tokensTypes[] = constant($tokenName);
|
||||
}
|
||||
|
||||
$data[$keyword.'FirstParam'] = [
|
||||
'/* testReservedKeyword'.ucfirst($keyword).'1 */',
|
||||
$tokensTypes,
|
||||
$keyword,
|
||||
];
|
||||
|
||||
$data[$keyword.'SecondParam'] = [
|
||||
'/* testReservedKeyword'.ucfirst($keyword).'2 */',
|
||||
$tokensTypes,
|
||||
$keyword,
|
||||
];
|
||||
}//end foreach
|
||||
|
||||
return $data;
|
||||
|
||||
}//end dataReservedKeywordsAsName()
|
||||
|
||||
|
||||
}//end class
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Null safe operator.
|
||||
*/
|
||||
|
||||
/* testObjectOperator */
|
||||
echo $obj->foo;
|
||||
|
||||
/* testNullsafeObjectOperator */
|
||||
echo $obj?->foo;
|
||||
|
||||
/* testNullsafeObjectOperatorWriteContext */
|
||||
// Intentional parse error, but not the concern of the tokenizer.
|
||||
$foo?->bar->baz = 'baz';
|
||||
|
||||
/* testTernaryThen */
|
||||
echo $obj ? $obj->prop : $other->prop;
|
||||
|
||||
/* testParseErrorWhitespaceNotAllowed */
|
||||
echo $obj ?
|
||||
-> foo;
|
||||
|
||||
/* testParseErrorCommentNotAllowed */
|
||||
echo $obj ?/*comment*/-> foo;
|
||||
|
||||
/* testLiveCoding */
|
||||
// Intentional parse error. This has to be the last test in the file.
|
||||
echo $obj?
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the backfill for the PHP >= 8.0 nullsafe object operator.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
|
||||
class NullsafeObjectOperatorTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
/**
|
||||
* Tokens to search for.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $find = [
|
||||
T_NULLSAFE_OBJECT_OPERATOR,
|
||||
T_OBJECT_OPERATOR,
|
||||
T_INLINE_THEN,
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Test that a normal object operator is still tokenized as such.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testObjectOperator()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$operator = $this->getTargetToken('/* testObjectOperator */', $this->find);
|
||||
$this->assertSame(T_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is object operator');
|
||||
$this->assertSame('T_OBJECT_OPERATOR', $tokens[$operator]['type'], 'Failed asserting type is object operator');
|
||||
|
||||
}//end testObjectOperator()
|
||||
|
||||
|
||||
/**
|
||||
* Test that a nullsafe object operator is tokenized as such.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataNullsafeObjectOperator
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNullsafeObjectOperator($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$operator = $this->getTargetToken($testMarker, $this->find);
|
||||
$this->assertSame(T_NULLSAFE_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is nullsafe object operator');
|
||||
$this->assertSame('T_NULLSAFE_OBJECT_OPERATOR', $tokens[$operator]['type'], 'Failed asserting type is nullsafe object operator');
|
||||
|
||||
}//end testNullsafeObjectOperator()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testNullsafeObjectOperator()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataNullsafeObjectOperator()
|
||||
{
|
||||
return [
|
||||
['/* testNullsafeObjectOperator */'],
|
||||
['/* testNullsafeObjectOperatorWriteContext */'],
|
||||
];
|
||||
|
||||
}//end dataNullsafeObjectOperator()
|
||||
|
||||
|
||||
/**
|
||||
* Test that a question mark not followed by an object operator is tokenized as T_TERNARY_THEN.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
* @param bool $testObjectOperator Whether to test for the next non-empty token being tokenized
|
||||
* as an object operator.
|
||||
*
|
||||
* @dataProvider dataTernaryThen
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTernaryThen($testMarker, $testObjectOperator=false)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$operator = $this->getTargetToken($testMarker, $this->find);
|
||||
$this->assertSame(T_INLINE_THEN, $tokens[$operator]['code'], 'Failed asserting code is inline then');
|
||||
$this->assertSame('T_INLINE_THEN', $tokens[$operator]['type'], 'Failed asserting type is inline then');
|
||||
|
||||
if ($testObjectOperator === true) {
|
||||
$next = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($operator + 1), null, true);
|
||||
$this->assertSame(T_OBJECT_OPERATOR, $tokens[$next]['code'], 'Failed asserting code is object operator');
|
||||
$this->assertSame('T_OBJECT_OPERATOR', $tokens[$next]['type'], 'Failed asserting type is object operator');
|
||||
}
|
||||
|
||||
}//end testTernaryThen()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testTernaryThen()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataTernaryThen()
|
||||
{
|
||||
return [
|
||||
['/* testTernaryThen */'],
|
||||
[
|
||||
'/* testParseErrorWhitespaceNotAllowed */',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'/* testParseErrorCommentNotAllowed */',
|
||||
true,
|
||||
],
|
||||
['/* testLiveCoding */'],
|
||||
];
|
||||
|
||||
}//end dataTernaryThen()
|
||||
|
||||
|
||||
}//end class
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/* testClassExtends */
|
||||
class Foo extends namespace\Bar {}
|
||||
|
||||
/* testClassImplements */
|
||||
$anon = new class implements namespace\Foo {}
|
||||
|
||||
/* testInterfaceExtends */
|
||||
interface FooBar extends namespace\BarFoo {}
|
||||
|
||||
/* testFunctionReturnType */
|
||||
function foo() : namespace\Baz {}
|
||||
|
||||
/* testClosureReturnType */
|
||||
$closure = function () : namespace\Baz {};
|
||||
|
||||
/* testArrowFunctionReturnType */
|
||||
$fn = fn() : namespace\Baz => new namespace\Baz;
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the adding of the "bracket_opener/closer" keys to use group tokens.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class ScopeSettingWithNamespaceOperatorTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that the scope opener/closers are set correctly when the namespace keyword is encountered as an operator.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target tokens in the test file.
|
||||
* @param int|string[] $tokenTypes The token type to search for.
|
||||
* @param int|string[] $open Optional. The token type for the scope opener.
|
||||
* @param int|string[] $close Optional. The token type for the scope closer.
|
||||
*
|
||||
* @dataProvider dataScopeSetting
|
||||
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testScopeSetting($testMarker, $tokenTypes, $open=T_OPEN_CURLY_BRACKET, $close=T_CLOSE_CURLY_BRACKET)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$target = $this->getTargetToken($testMarker, $tokenTypes);
|
||||
$opener = $this->getTargetToken($testMarker, $open);
|
||||
$closer = $this->getTargetToken($testMarker, $close);
|
||||
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$target], 'Scope opener missing');
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$target], 'Scope closer missing');
|
||||
$this->assertSame($opener, $tokens[$target]['scope_opener'], 'Scope opener not same');
|
||||
$this->assertSame($closer, $tokens[$target]['scope_closer'], 'Scope closer not same');
|
||||
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Scope opener missing for open curly');
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Scope closer missing for open curly');
|
||||
$this->assertSame($opener, $tokens[$opener]['scope_opener'], 'Scope opener not same for open curly');
|
||||
$this->assertSame($closer, $tokens[$opener]['scope_closer'], 'Scope closer not same for open curly');
|
||||
|
||||
$this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Scope opener missing for close curly');
|
||||
$this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Scope closer missing for close curly');
|
||||
$this->assertSame($opener, $tokens[$closer]['scope_opener'], 'Scope opener not same for close curly');
|
||||
$this->assertSame($closer, $tokens[$closer]['scope_closer'], 'Scope closer not same for close curly');
|
||||
|
||||
}//end testScopeSetting()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testScopeSetting()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataScopeSetting()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testClassExtends */',
|
||||
[T_CLASS],
|
||||
],
|
||||
[
|
||||
'/* testClassImplements */',
|
||||
[T_ANON_CLASS],
|
||||
],
|
||||
[
|
||||
'/* testInterfaceExtends */',
|
||||
[T_INTERFACE],
|
||||
],
|
||||
[
|
||||
'/* testFunctionReturnType */',
|
||||
[T_FUNCTION],
|
||||
],
|
||||
[
|
||||
'/* testClosureReturnType */',
|
||||
[T_CLOSURE],
|
||||
],
|
||||
[
|
||||
'/* testArrowFunctionReturnType */',
|
||||
[T_FN],
|
||||
[T_FN_ARROW],
|
||||
[T_SEMICOLON],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataScopeSetting()
|
||||
|
||||
|
||||
}//end class
|
||||
Vendored
+111
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Square brackets.
|
||||
*/
|
||||
|
||||
/* testArrayAccess1 */
|
||||
$var = $array[10];
|
||||
|
||||
$var = $array[++$y]/* testArrayAccess2 */[$x];
|
||||
|
||||
/* testArrayAssignment */
|
||||
$array[] = $var;
|
||||
|
||||
/* testFunctionCallDereferencing */
|
||||
$var = function_call()[$x];
|
||||
|
||||
/* testMethodCallDereferencing */
|
||||
$var = $obj->function_call()[$x];
|
||||
|
||||
/* testStaticMethodCallDereferencing */
|
||||
$var = ClassName::function_call()[$x];
|
||||
|
||||
/* testPropertyDereferencing */
|
||||
$var = $obj->property[2];
|
||||
|
||||
/* testPropertyDereferencingWithInaccessibleName */
|
||||
$var = $ref->{'ref-type'}[1];
|
||||
|
||||
/* testStaticPropertyDereferencing */
|
||||
$var ClassName::$property[2];
|
||||
|
||||
/* testStringDereferencing */
|
||||
$var = 'PHP'[1];
|
||||
|
||||
/* testStringDereferencingDoubleQuoted */
|
||||
$var = "PHP"[$y];
|
||||
|
||||
/* testConstantDereferencing */
|
||||
$var = MY_CONSTANT[1];
|
||||
|
||||
/* testClassConstantDereferencing */
|
||||
$var ClassName::CONSTANT_NAME[2];
|
||||
|
||||
/* testMagicConstantDereferencing */
|
||||
$var = __FILE__[0];
|
||||
|
||||
/* testArrayAccessCurlyBraces */
|
||||
$var = $array{'key'}['key'];
|
||||
|
||||
/* testArrayLiteralDereferencing */
|
||||
echo array(1, 2, 3)[0];
|
||||
|
||||
echo [1, 2, 3]/* testShortArrayLiteralDereferencing */[0];
|
||||
|
||||
/* testClassMemberDereferencingOnInstantiation1 */
|
||||
(new foo)[0];
|
||||
|
||||
/* testClassMemberDereferencingOnInstantiation2 */
|
||||
$a = (new Foo( array(1, array(4, 5), 3) ))[1][0];
|
||||
|
||||
/* testClassMemberDereferencingOnClone */
|
||||
echo (clone $iterable)[20];
|
||||
|
||||
/* testNullsafeMethodCallDereferencing */
|
||||
$var = $obj?->function_call()[$x];
|
||||
|
||||
/* testInterpolatedStringDereferencing */
|
||||
$var = "PHP{$rocks}"[1];
|
||||
|
||||
/*
|
||||
* Short array brackets.
|
||||
*/
|
||||
|
||||
/* testShortArrayDeclarationEmpty */
|
||||
$array = [];
|
||||
|
||||
/* testShortArrayDeclarationWithOneValue */
|
||||
$array = [1];
|
||||
|
||||
/* testShortArrayDeclarationWithMultipleValues */
|
||||
$array = [1, 2, 3];
|
||||
|
||||
/* testShortArrayDeclarationWithDereferencing */
|
||||
echo [1, 2, 3][0];
|
||||
|
||||
/* testShortListDeclaration */
|
||||
[ $a, $b ] = $array;
|
||||
|
||||
[ $a, $b, /* testNestedListDeclaration */, [$c, $d]] = $array;
|
||||
|
||||
/* testArrayWithinFunctionCall */
|
||||
$var = functionCall([$x, $y]);
|
||||
|
||||
if ( true ) {
|
||||
/* testShortListDeclarationAfterBracedControlStructure */
|
||||
[ $a ] = [ 'hi' ];
|
||||
}
|
||||
|
||||
if ( true )
|
||||
/* testShortListDeclarationAfterNonBracedControlStructure */
|
||||
[ $a ] = [ 'hi' ];
|
||||
|
||||
if ( true ) :
|
||||
/* testShortListDeclarationAfterAlternativeControlStructure */
|
||||
[ $a ] = [ 'hi' ];
|
||||
endif;
|
||||
|
||||
/* testLiveCoding */
|
||||
// Intentional parse error. This has to be the last test in the file.
|
||||
$array = [
|
||||
Vendored
+135
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the conversion of square bracket tokens to short array tokens.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class ShortArrayTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that real square brackets are still tokenized as square brackets.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataSquareBrackets
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSquareBrackets($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]);
|
||||
$this->assertSame(T_OPEN_SQUARE_BRACKET, $tokens[$opener]['code']);
|
||||
$this->assertSame('T_OPEN_SQUARE_BRACKET', $tokens[$opener]['type']);
|
||||
|
||||
if (isset($tokens[$opener]['bracket_closer']) === true) {
|
||||
$closer = $tokens[$opener]['bracket_closer'];
|
||||
$this->assertSame(T_CLOSE_SQUARE_BRACKET, $tokens[$closer]['code']);
|
||||
$this->assertSame('T_CLOSE_SQUARE_BRACKET', $tokens[$closer]['type']);
|
||||
}
|
||||
|
||||
}//end testSquareBrackets()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testSquareBrackets()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataSquareBrackets()
|
||||
{
|
||||
return [
|
||||
'array access 1' => ['/* testArrayAccess1 */'],
|
||||
'array access 2' => ['/* testArrayAccess2 */'],
|
||||
'array assignment' => ['/* testArrayAssignment */'],
|
||||
'function call dereferencing' => ['/* testFunctionCallDereferencing */'],
|
||||
'method call dereferencing' => ['/* testMethodCallDereferencing */'],
|
||||
'static method call dereferencing' => ['/* testStaticMethodCallDereferencing */'],
|
||||
'property dereferencing' => ['/* testPropertyDereferencing */'],
|
||||
'property dereferencing with inaccessable name' => ['/* testPropertyDereferencingWithInaccessibleName */'],
|
||||
'static property dereferencing' => ['/* testStaticPropertyDereferencing */'],
|
||||
'string dereferencing single quotes' => ['/* testStringDereferencing */'],
|
||||
'string dereferencing double quotes' => ['/* testStringDereferencingDoubleQuoted */'],
|
||||
'global constant dereferencing' => ['/* testConstantDereferencing */'],
|
||||
'class constant dereferencing' => ['/* testClassConstantDereferencing */'],
|
||||
'magic constant dereferencing' => ['/* testMagicConstantDereferencing */'],
|
||||
'array access with curly braces' => ['/* testArrayAccessCurlyBraces */'],
|
||||
'array literal dereferencing' => ['/* testArrayLiteralDereferencing */'],
|
||||
'short array literal dereferencing' => ['/* testShortArrayLiteralDereferencing */'],
|
||||
'class member dereferencing on instantiation 1' => ['/* testClassMemberDereferencingOnInstantiation1 */'],
|
||||
'class member dereferencing on instantiation 2' => ['/* testClassMemberDereferencingOnInstantiation2 */'],
|
||||
'class member dereferencing on clone' => ['/* testClassMemberDereferencingOnClone */'],
|
||||
'nullsafe method call dereferencing' => ['/* testNullsafeMethodCallDereferencing */'],
|
||||
'interpolated string dereferencing' => ['/* testInterpolatedStringDereferencing */'],
|
||||
'live coding' => ['/* testLiveCoding */'],
|
||||
];
|
||||
|
||||
}//end dataSquareBrackets()
|
||||
|
||||
|
||||
/**
|
||||
* Test that short arrays and short lists are still tokenized as short arrays.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataShortArrays
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testShortArrays($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]);
|
||||
$this->assertSame(T_OPEN_SHORT_ARRAY, $tokens[$opener]['code']);
|
||||
$this->assertSame('T_OPEN_SHORT_ARRAY', $tokens[$opener]['type']);
|
||||
|
||||
if (isset($tokens[$opener]['bracket_closer']) === true) {
|
||||
$closer = $tokens[$opener]['bracket_closer'];
|
||||
$this->assertSame(T_CLOSE_SHORT_ARRAY, $tokens[$closer]['code']);
|
||||
$this->assertSame('T_CLOSE_SHORT_ARRAY', $tokens[$closer]['type']);
|
||||
}
|
||||
|
||||
}//end testShortArrays()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testShortArrays()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataShortArrays()
|
||||
{
|
||||
return [
|
||||
'short array empty' => ['/* testShortArrayDeclarationEmpty */'],
|
||||
'short array with value' => ['/* testShortArrayDeclarationWithOneValue */'],
|
||||
'short array with values' => ['/* testShortArrayDeclarationWithMultipleValues */'],
|
||||
'short array with dereferencing' => ['/* testShortArrayDeclarationWithDereferencing */'],
|
||||
'short list' => ['/* testShortListDeclaration */'],
|
||||
'short list nested' => ['/* testNestedListDeclaration */'],
|
||||
'short array within function call' => ['/* testArrayWithinFunctionCall */'],
|
||||
'short list after braced control structure' => ['/* testShortListDeclarationAfterBracedControlStructure */'],
|
||||
'short list after non-braced control structure' => ['/* testShortListDeclarationAfterNonBracedControlStructure */'],
|
||||
'short list after alternative control structure' => ['/* testShortListDeclarationAfterAlternativeControlStructure */'],
|
||||
];
|
||||
|
||||
}//end dataShortArrays()
|
||||
|
||||
|
||||
}//end class
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
/* testSingleLineSlashComment */
|
||||
// Comment
|
||||
|
||||
/* testSingleLineSlashCommentTrailing */
|
||||
echo 'a'; // Comment
|
||||
|
||||
/* testSingleLineSlashAnnotation */
|
||||
// phpcs:disable Stnd.Cat
|
||||
|
||||
/* testMultiLineSlashComment */
|
||||
// Comment1
|
||||
// Comment2
|
||||
// Comment3
|
||||
|
||||
/* testMultiLineSlashCommentWithIndent */
|
||||
// Comment1
|
||||
// Comment2
|
||||
// Comment3
|
||||
|
||||
/* testMultiLineSlashCommentWithAnnotationStart */
|
||||
// phpcs:ignore Stnd.Cat
|
||||
// Comment2
|
||||
// Comment3
|
||||
|
||||
/* testMultiLineSlashCommentWithAnnotationMiddle */
|
||||
// Comment1
|
||||
// @phpcs:ignore Stnd.Cat
|
||||
// Comment3
|
||||
|
||||
/* testMultiLineSlashCommentWithAnnotationEnd */
|
||||
// Comment1
|
||||
// Comment2
|
||||
// phpcs:ignore Stnd.Cat
|
||||
|
||||
|
||||
/* testSingleLineStarComment */
|
||||
/* Single line star comment */
|
||||
|
||||
/* testSingleLineStarCommentTrailing */
|
||||
echo 'a'; /* Comment */
|
||||
|
||||
/* testSingleLineStarAnnotation */
|
||||
/* phpcs:ignore Stnd.Cat */
|
||||
|
||||
/* testMultiLineStarComment */
|
||||
/* Comment1
|
||||
* Comment2
|
||||
* Comment3 */
|
||||
|
||||
/* testMultiLineStarCommentWithIndent */
|
||||
/* Comment1
|
||||
* Comment2
|
||||
* Comment3 */
|
||||
|
||||
/* testMultiLineStarCommentWithAnnotationStart */
|
||||
/* @phpcs:ignore Stnd.Cat
|
||||
* Comment2
|
||||
* Comment3 */
|
||||
|
||||
/* testMultiLineStarCommentWithAnnotationMiddle */
|
||||
/* Comment1
|
||||
* phpcs:ignore Stnd.Cat
|
||||
* Comment3 */
|
||||
|
||||
/* testMultiLineStarCommentWithAnnotationEnd */
|
||||
/* Comment1
|
||||
* Comment2
|
||||
* phpcs:ignore Stnd.Cat */
|
||||
|
||||
|
||||
/* testSingleLineDocblockComment */
|
||||
/** Comment */
|
||||
|
||||
/* testSingleLineDocblockCommentTrailing */
|
||||
$prop = 123; /** Comment */
|
||||
|
||||
/* testSingleLineDocblockAnnotation */
|
||||
/** phpcs:ignore Stnd.Cat.Sniff */
|
||||
|
||||
/* testMultiLineDocblockComment */
|
||||
/**
|
||||
* Comment1
|
||||
* Comment2
|
||||
*
|
||||
* @tag Comment
|
||||
*/
|
||||
|
||||
/* testMultiLineDocblockCommentWithIndent */
|
||||
/**
|
||||
* Comment1
|
||||
* Comment2
|
||||
*
|
||||
* @tag Comment
|
||||
*/
|
||||
|
||||
/* testMultiLineDocblockCommentWithAnnotation */
|
||||
/**
|
||||
* Comment
|
||||
*
|
||||
* phpcs:ignore Stnd.Cat
|
||||
* @tag Comment
|
||||
*/
|
||||
|
||||
/* testMultiLineDocblockCommentWithTagAnnotation */
|
||||
/**
|
||||
* Comment
|
||||
*
|
||||
* @phpcs:ignore Stnd.Cat
|
||||
* @tag Comment
|
||||
*/
|
||||
|
||||
/* testSingleLineHashComment */
|
||||
# Comment
|
||||
|
||||
/* testSingleLineHashCommentTrailing */
|
||||
echo 'a'; # Comment
|
||||
|
||||
/* testMultiLineHashComment */
|
||||
# Comment1
|
||||
# Comment2
|
||||
# Comment3
|
||||
|
||||
/* testMultiLineHashCommentWithIndent */
|
||||
# Comment1
|
||||
# Comment2
|
||||
# Comment3
|
||||
|
||||
/* testSingleLineSlashCommentNoNewLineAtEnd */
|
||||
// Slash ?>
|
||||
<?php
|
||||
|
||||
/* testSingleLineHashCommentNoNewLineAtEnd */
|
||||
# Hash ?>
|
||||
<?php
|
||||
|
||||
/* testCommentAtEndOfFile */
|
||||
/* Comment
|
||||
+1056
File diff suppressed because it is too large
Load Diff
+63
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/* testSingleLineSlashComment */
|
||||
// Comment
|
||||
|
||||
/* testSingleLineSlashCommentTrailing */
|
||||
echo 'a'; // Comment
|
||||
|
||||
/* testSingleLineSlashAnnotation */
|
||||
// phpcs:disable Stnd.Cat
|
||||
|
||||
/* testMultiLineSlashComment */
|
||||
// Comment1
|
||||
// Comment2
|
||||
// Comment3
|
||||
|
||||
/* testMultiLineSlashCommentWithIndent */
|
||||
// Comment1
|
||||
// Comment2
|
||||
// Comment3
|
||||
|
||||
/* testMultiLineSlashCommentWithAnnotationStart */
|
||||
// phpcs:ignore Stnd.Cat
|
||||
// Comment2
|
||||
// Comment3
|
||||
|
||||
/* testMultiLineSlashCommentWithAnnotationMiddle */
|
||||
// Comment1
|
||||
// @phpcs:ignore Stnd.Cat
|
||||
// Comment3
|
||||
|
||||
/* testMultiLineSlashCommentWithAnnotationEnd */
|
||||
// Comment1
|
||||
// Comment2
|
||||
// phpcs:ignore Stnd.Cat
|
||||
|
||||
|
||||
/* testSingleLineSlashCommentNoNewLineAtEnd */
|
||||
// Slash ?>
|
||||
<?php
|
||||
|
||||
/* testSingleLineHashComment */
|
||||
# Comment
|
||||
|
||||
/* testSingleLineHashCommentTrailing */
|
||||
echo 'a'; # Comment
|
||||
|
||||
/* testMultiLineHashComment */
|
||||
# Comment1
|
||||
# Comment2
|
||||
# Comment3
|
||||
|
||||
/* testMultiLineHashCommentWithIndent */
|
||||
# Comment1
|
||||
# Comment2
|
||||
# Comment3
|
||||
|
||||
/* testSingleLineHashCommentNoNewLineAtEnd */
|
||||
# Hash ?>
|
||||
<?php
|
||||
|
||||
/* testCommentAtEndOfFile */
|
||||
/* Comment
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the comment tokenization with Windows line endings.
|
||||
*
|
||||
* Basically the same as the StableCommentWhitespaceTest, but now for
|
||||
* Windows line endings.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
|
||||
class StableCommentWhitespaceWinTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that comment tokenization with new lines at the end of the comment is stable.
|
||||
*
|
||||
* @param string $testMarker The comment prefacing the test.
|
||||
* @param array $expectedTokens The tokenization expected.
|
||||
*
|
||||
* @dataProvider dataCommentTokenization
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCommentTokenization($testMarker, $expectedTokens)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
$comment = $this->getTargetToken($testMarker, Tokens::$commentTokens);
|
||||
|
||||
foreach ($expectedTokens as $key => $tokenInfo) {
|
||||
$this->assertSame(constant($tokenInfo['type']), $tokens[$comment]['code']);
|
||||
$this->assertSame($tokenInfo['type'], $tokens[$comment]['type']);
|
||||
$this->assertSame($tokenInfo['content'], $tokens[$comment]['content']);
|
||||
|
||||
++$comment;
|
||||
}
|
||||
|
||||
}//end testCommentTokenization()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testCommentTokenization()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataCommentTokenization()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'/* testSingleLineSlashComment */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testSingleLineSlashCommentTrailing */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testSingleLineSlashAnnotation */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_PHPCS_DISABLE',
|
||||
'content' => '// phpcs:disable Stnd.Cat
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultiLineSlashComment */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment1
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment2
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment3
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultiLineSlashCommentWithIndent */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment1
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => ' ',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment2
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => ' ',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment3
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultiLineSlashCommentWithAnnotationStart */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_PHPCS_IGNORE',
|
||||
'content' => '// phpcs:ignore Stnd.Cat
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment2
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment3
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultiLineSlashCommentWithAnnotationMiddle */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment1
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_PHPCS_IGNORE',
|
||||
'content' => '// @phpcs:ignore Stnd.Cat
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment3
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultiLineSlashCommentWithAnnotationEnd */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment1
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Comment2
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_PHPCS_IGNORE',
|
||||
'content' => '// phpcs:ignore Stnd.Cat
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testSingleLineSlashCommentNoNewLineAtEnd */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '// Slash ',
|
||||
],
|
||||
[
|
||||
'type' => 'T_CLOSE_TAG',
|
||||
'content' => '?>
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testSingleLineHashComment */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '# Comment
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testSingleLineHashCommentTrailing */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '# Comment
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultiLineHashComment */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '# Comment1
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '# Comment2
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '# Comment3
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultiLineHashCommentWithIndent */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '# Comment1
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => ' ',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '# Comment2
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => ' ',
|
||||
],
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '# Comment3
|
||||
',
|
||||
],
|
||||
[
|
||||
'type' => 'T_WHITESPACE',
|
||||
'content' => '
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testSingleLineHashCommentNoNewLineAtEnd */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '# Hash ',
|
||||
],
|
||||
[
|
||||
'type' => 'T_CLOSE_TAG',
|
||||
'content' => '?>
|
||||
',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testCommentAtEndOfFile */',
|
||||
[
|
||||
[
|
||||
'type' => 'T_COMMENT',
|
||||
'content' => '/* Comment',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataCommentTokenization()
|
||||
|
||||
|
||||
}//end class
|
||||
lib/zxcvbn-php-master/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc
Vendored
+120
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Type intersection or bitwise and.
|
||||
*/
|
||||
|
||||
/* testBitwiseAnd1 */
|
||||
$result = $value & $test /* testBitwiseAnd2 */ & $another;
|
||||
|
||||
class TypeIntersection
|
||||
{
|
||||
/* testTypeIntersectionPropertySimple */
|
||||
public static Foo&Bar $obj;
|
||||
|
||||
/* testTypeIntersectionPropertyReverseModifierOrder */
|
||||
static protected Something&Nothing $somethingNothing /* testBitwiseAndPropertyDefaultValue */ = E_WARNING & E_NOTICE;
|
||||
|
||||
private
|
||||
/* testTypeIntersectionPropertyMulti1 */
|
||||
Foo &
|
||||
/* testTypeIntersectionPropertyMulti2 */
|
||||
Traversable & // phpcs:ignore Stnd.Cat.Sniff
|
||||
Boo
|
||||
/* testTypeIntersectionPropertyMulti3 */
|
||||
& Bar $multi;
|
||||
|
||||
/* testTypeIntersectionPropertyNamespaceRelative */
|
||||
public namespace\Sub\NameA&namespace\Sub\NameB $namespaceRelative;
|
||||
|
||||
/* testTypeIntersectionPropertyPartiallyQualified */
|
||||
public Partially\Qualified\NameA&Partially\Qualified\NameB $partiallyQual;
|
||||
|
||||
/* testTypeIntersectionPropertyFullyQualified */
|
||||
public \Fully\Qualified\NameA&\Fully\Qualified\NameB $fullyQual;
|
||||
|
||||
/* testTypeIntersectionPropertyWithReadOnlyKeyword */
|
||||
protected readonly Foo&Bar $fooBar;
|
||||
|
||||
public function paramTypes(
|
||||
/* testTypeIntersectionParam1 */
|
||||
Foo&Bar $paramA /* testBitwiseAndParamDefaultValue */ = CONSTANT_A & CONSTANT_B,
|
||||
|
||||
/* testTypeIntersectionParam2 */
|
||||
Foo&\Bar /* testTypeIntersectionParam3 */ &Baz /* testBitwiseAnd3 */ &...$paramB = null,
|
||||
) {
|
||||
/* testBitwiseAnd4 */
|
||||
return (($a1 ^ $b1) &($a2 ^ $b2)) + $c;
|
||||
}
|
||||
|
||||
public function identifierNames(
|
||||
/* testTypeIntersectionParamNamespaceRelative */
|
||||
namespace\Sub\NameA&namespace\Sub\NameB $paramA,
|
||||
/* testTypeIntersectionParamPartiallyQualified */
|
||||
Partially\Qualified\NameA&Partially\Qualified\NameB $paramB,
|
||||
/* testTypeIntersectionParamFullyQualified */
|
||||
\Fully\Qualified\NameA&\Fully\Qualified\NameB $paramC,
|
||||
) {}
|
||||
|
||||
/* testTypeIntersectionReturnType */
|
||||
public function returnType() : Foo&Bar {}
|
||||
|
||||
/* testTypeIntersectionConstructorPropertyPromotion */
|
||||
public function __construct( public Foo&Bar $property) {}
|
||||
|
||||
/* testTypeIntersectionAbstractMethodReturnType1 */
|
||||
abstract public function abstractMethod(): Foo&Bar /* testTypeIntersectionAbstractMethodReturnType2 */ &Baz;
|
||||
|
||||
/* testTypeIntersectionReturnTypeNamespaceRelative */
|
||||
public function identifierNamesReturnRelative() : namespace\Sub\NameA&namespace\Sub\NameB {}
|
||||
|
||||
/* testTypeIntersectionReturnPartiallyQualified */
|
||||
public function identifierNamesReturnPQ() : Partially\Qualified\NameA&Partially\Qualified\NameB {}
|
||||
|
||||
/* testTypeIntersectionReturnFullyQualified */
|
||||
public function identifierNamesReturnFQ() : \Fully\Qualified\NameA&\Fully\Qualified\NameB {}
|
||||
}
|
||||
|
||||
/* testTypeIntersectionClosureParamIllegalNullable */
|
||||
$closureWithParamType = function (?Foo&Bar $string) {};
|
||||
|
||||
function globalFunctionWithSpreadAndReference(
|
||||
/* testTypeIntersectionWithReference */
|
||||
Foo&Bar /* testBitwiseAnd5 */ &$paramA,
|
||||
/* testTypeIntersectionWithSpreadOperator */
|
||||
Foo&Bar ...$paramB
|
||||
) {}
|
||||
|
||||
/* testBitwiseAndClosureParamDefault */
|
||||
$closureWithReturnType = function ($string = NONSENSE & FAKE)/* testTypeIntersectionClosureReturn */ : \Package\MyA&PackageB {};
|
||||
|
||||
/* testTypeIntersectionArrowParam */
|
||||
$arrowWithParamType = fn (Foo&Bar $param, /* testBitwiseAndArrowParamDefault */ ?int $int = CONSTA & CONSTB )
|
||||
/* testBitwiseAndArrowExpression */
|
||||
=> $param & $int;
|
||||
|
||||
/* testTypeIntersectionArrowReturnType */
|
||||
$arrowWithReturnType = fn ($param) : Foo&Bar => $param * 10;
|
||||
|
||||
/* testBitwiseAndInArrayKey */
|
||||
$array = array(
|
||||
A & B => /* testBitwiseAndInArrayValue */ B & C
|
||||
);
|
||||
|
||||
/* testBitwiseAndInShortArrayKey */
|
||||
$array = [
|
||||
A & B => /* testBitwiseAndInShortArrayValue */ B & C
|
||||
];
|
||||
|
||||
/* testBitwiseAndNonArrowFnFunctionCall */
|
||||
$obj->fn($something & $else);
|
||||
|
||||
/* testBitwiseAnd6 */
|
||||
function &fn(/* testTypeIntersectionNonArrowFunctionDeclaration */ Foo&Bar $something) {}
|
||||
|
||||
/* testTypeIntersectionWithInvalidTypes */
|
||||
function (int&string $var) {};
|
||||
|
||||
/* testLiveCoding */
|
||||
// Intentional parse error. This has to be the last test in the file.
|
||||
return function( Foo&
|
||||
lib/zxcvbn-php-master/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php
Vendored
+138
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the conversion of bitwise and tokens to type intersection tokens.
|
||||
*
|
||||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
|
||||
* @author Jaroslav Hanslík <kukulich@kukulich.cz>
|
||||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer;
|
||||
|
||||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
|
||||
|
||||
class TypeIntersectionTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test that non-intersection type bitwise and tokens are still tokenized as bitwise and.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataBitwiseAnd
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBitwiseAnd($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$opener = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]);
|
||||
$this->assertSame(T_BITWISE_AND, $tokens[$opener]['code']);
|
||||
$this->assertSame('T_BITWISE_AND', $tokens[$opener]['type']);
|
||||
|
||||
}//end testBitwiseAnd()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testBitwiseAnd()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataBitwiseAnd()
|
||||
{
|
||||
return [
|
||||
['/* testBitwiseAnd1 */'],
|
||||
['/* testBitwiseAnd2 */'],
|
||||
['/* testBitwiseAndPropertyDefaultValue */'],
|
||||
['/* testBitwiseAndParamDefaultValue */'],
|
||||
['/* testBitwiseAnd3 */'],
|
||||
['/* testBitwiseAnd4 */'],
|
||||
['/* testBitwiseAnd5 */'],
|
||||
['/* testBitwiseAndClosureParamDefault */'],
|
||||
['/* testBitwiseAndArrowParamDefault */'],
|
||||
['/* testBitwiseAndArrowExpression */'],
|
||||
['/* testBitwiseAndInArrayKey */'],
|
||||
['/* testBitwiseAndInArrayValue */'],
|
||||
['/* testBitwiseAndInShortArrayKey */'],
|
||||
['/* testBitwiseAndInShortArrayValue */'],
|
||||
['/* testBitwiseAndNonArrowFnFunctionCall */'],
|
||||
['/* testBitwiseAnd6 */'],
|
||||
['/* testLiveCoding */'],
|
||||
];
|
||||
|
||||
}//end dataBitwiseAnd()
|
||||
|
||||
|
||||
/**
|
||||
* Test that bitwise and tokens when used as part of a intersection type are tokenized as `T_TYPE_INTERSECTION`.
|
||||
*
|
||||
* @param string $testMarker The comment which prefaces the target token in the test file.
|
||||
*
|
||||
* @dataProvider dataTypeIntersection
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTypeIntersection($testMarker)
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$opener = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]);
|
||||
$this->assertSame(T_TYPE_INTERSECTION, $tokens[$opener]['code']);
|
||||
$this->assertSame('T_TYPE_INTERSECTION', $tokens[$opener]['type']);
|
||||
|
||||
}//end testTypeIntersection()
|
||||
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @see testTypeIntersection()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataTypeIntersection()
|
||||
{
|
||||
return [
|
||||
['/* testTypeIntersectionPropertySimple */'],
|
||||
['/* testTypeIntersectionPropertyReverseModifierOrder */'],
|
||||
['/* testTypeIntersectionPropertyMulti1 */'],
|
||||
['/* testTypeIntersectionPropertyMulti2 */'],
|
||||
['/* testTypeIntersectionPropertyMulti3 */'],
|
||||
['/* testTypeIntersectionPropertyNamespaceRelative */'],
|
||||
['/* testTypeIntersectionPropertyPartiallyQualified */'],
|
||||
['/* testTypeIntersectionPropertyFullyQualified */'],
|
||||
['/* testTypeIntersectionPropertyWithReadOnlyKeyword */'],
|
||||
['/* testTypeIntersectionParam1 */'],
|
||||
['/* testTypeIntersectionParam2 */'],
|
||||
['/* testTypeIntersectionParam3 */'],
|
||||
['/* testTypeIntersectionParamNamespaceRelative */'],
|
||||
['/* testTypeIntersectionParamPartiallyQualified */'],
|
||||
['/* testTypeIntersectionParamFullyQualified */'],
|
||||
['/* testTypeIntersectionReturnType */'],
|
||||
['/* testTypeIntersectionConstructorPropertyPromotion */'],
|
||||
['/* testTypeIntersectionAbstractMethodReturnType1 */'],
|
||||
['/* testTypeIntersectionAbstractMethodReturnType2 */'],
|
||||
['/* testTypeIntersectionReturnTypeNamespaceRelative */'],
|
||||
['/* testTypeIntersectionReturnPartiallyQualified */'],
|
||||
['/* testTypeIntersectionReturnFullyQualified */'],
|
||||
['/* testTypeIntersectionClosureParamIllegalNullable */'],
|
||||
['/* testTypeIntersectionWithReference */'],
|
||||
['/* testTypeIntersectionWithSpreadOperator */'],
|
||||
['/* testTypeIntersectionClosureReturn */'],
|
||||
['/* testTypeIntersectionArrowParam */'],
|
||||
['/* testTypeIntersectionArrowReturnType */'],
|
||||
['/* testTypeIntersectionNonArrowFunctionDeclaration */'],
|
||||
['/* testTypeIntersectionWithInvalidTypes */'],
|
||||
];
|
||||
|
||||
}//end dataTypeIntersection()
|
||||
|
||||
|
||||
}//end class
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
/* testNamespaceDeclaration */
|
||||
namespace Package;
|
||||
|
||||
/* testNamespaceDeclarationWithLevels */
|
||||
namespace Vendor\SubLevel\Domain;
|
||||
|
||||
/* testUseStatement */
|
||||
use ClassName;
|
||||
|
||||
/* testUseStatementWithLevels */
|
||||
use Vendor\Level\Domain;
|
||||
|
||||
/* testFunctionUseStatement */
|
||||
use function function_name;
|
||||
|
||||
/* testFunctionUseStatementWithLevels */
|
||||
use function Vendor\Level\function_in_ns;
|
||||
|
||||
/* testConstantUseStatement */
|
||||
use const CONSTANT_NAME;
|
||||
|
||||
/* testConstantUseStatementWithLevels */
|
||||
use const Vendor\Level\OTHER_CONSTANT;
|
||||
|
||||
/* testMultiUseUnqualified */
|
||||
use UnqualifiedClassName,
|
||||
/* testMultiUsePartiallyQualified */
|
||||
Sublevel\PartiallyClassName;
|
||||
|
||||
/* testGroupUseStatement */
|
||||
use Vendor\Level\{
|
||||
AnotherDomain,
|
||||
function function_grouped,
|
||||
const CONSTANT_GROUPED,
|
||||
Sub\YetAnotherDomain,
|
||||
function SubLevelA\function_grouped_too,
|
||||
const SubLevelB\CONSTANT_GROUPED_TOO,
|
||||
};
|
||||
|
||||
/* testClassName */
|
||||
class MyClass
|
||||
/* testExtendedFQN */
|
||||
extends \Vendor\Level\FQN
|
||||
/* testImplementsRelative */
|
||||
implements namespace\Name,
|
||||
/* testImplementsFQN */
|
||||
\Fully\Qualified,
|
||||
/* testImplementsUnqualified */
|
||||
Unqualified,
|
||||
/* testImplementsPartiallyQualified */
|
||||
Sub\Level\Name
|
||||
{
|
||||
/* testFunctionName */
|
||||
public function function_name(
|
||||
/* testTypeDeclarationRelative */
|
||||
?namespace\Name|object $paramA,
|
||||
|
||||
/* testTypeDeclarationFQN */
|
||||
\Fully\Qualified\Name $paramB,
|
||||
|
||||
/* testTypeDeclarationUnqualified */
|
||||
Unqualified|false $paramC,
|
||||
|
||||
/* testTypeDeclarationPartiallyQualified */
|
||||
?Sublevel\Name $paramD,
|
||||
|
||||
/* testReturnTypeFQN */
|
||||
) : ?\Name {
|
||||
|
||||
try {
|
||||
/* testFunctionCallRelative */
|
||||
echo NameSpace\function_name();
|
||||
|
||||
/* testFunctionCallFQN */
|
||||
echo \Vendor\Package\function_name();
|
||||
|
||||
/* testFunctionCallUnqualified */
|
||||
echo function_name();
|
||||
|
||||
/* testFunctionPartiallyQualified */
|
||||
echo Level\function_name();
|
||||
|
||||
/* testCatchRelative */
|
||||
} catch (namespace\SubLevel\Exception $e) {
|
||||
|
||||
/* testCatchFQN */
|
||||
} catch (\Exception $e) {
|
||||
|
||||
/* testCatchUnqualified */
|
||||
} catch (Exception $e) {
|
||||
|
||||
/* testCatchPartiallyQualified */
|
||||
} catch (Level\Exception $e) {
|
||||
}
|
||||
|
||||
/* testNewRelative */
|
||||
$obj = new namespace\ClassName();
|
||||
|
||||
/* testNewFQN */
|
||||
$obj = new \Vendor\ClassName();
|
||||
|
||||
/* testNewUnqualified */
|
||||
$obj = new ClassName;
|
||||
|
||||
/* testNewPartiallyQualified */
|
||||
$obj = new Level\ClassName;
|
||||
|
||||
/* testDoubleColonRelative */
|
||||
$value = namespace\ClassName::property;
|
||||
|
||||
/* testDoubleColonFQN */
|
||||
$value = \ClassName::static_function();
|
||||
|
||||
/* testDoubleColonUnqualified */
|
||||
$value = ClassName::CONSTANT_NAME;
|
||||
|
||||
/* testDoubleColonPartiallyQualified */
|
||||
$value = Level\ClassName::CONSTANT_NAME['key'];
|
||||
|
||||
/* testInstanceOfRelative */
|
||||
$is = $obj instanceof namespace\ClassName;
|
||||
|
||||
/* testInstanceOfFQN */
|
||||
if ($obj instanceof \Full\ClassName) {}
|
||||
|
||||
/* testInstanceOfUnqualified */
|
||||
if ($a === $b && $obj instanceof ClassName && true) {}
|
||||
|
||||
/* testInstanceOfPartiallyQualified */
|
||||
$is = $obj instanceof Partially\ClassName;
|
||||
}
|
||||
}
|
||||
|
||||
/* testInvalidInPHP8Whitespace */
|
||||
namespace \ Sublevel
|
||||
\ function_name();
|
||||
|
||||
/* testInvalidInPHP8Comments */
|
||||
$value = \Fully
|
||||
// phpcs:ignore Stnd.Cat.Sniff -- for reasons
|
||||
\Qualified
|
||||
/* comment */
|
||||
\Name
|
||||
// comment
|
||||
:: function_name();
|
||||
+1295
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,94 @@
|
||||
<?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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests;
|
||||
|
||||
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
+461
@@ -0,0 +1,461 @@
|
||||
<?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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Standards;
|
||||
|
||||
use PHP_CodeSniffer\Config;
|
||||
use PHP_CodeSniffer\Exceptions\RuntimeException;
|
||||
use PHP_CodeSniffer\Ruleset;
|
||||
use PHP_CodeSniffer\Files\LocalFile;
|
||||
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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$class = get_class($this);
|
||||
$this->standardsDir = $GLOBALS['PHP_CODESNIFFER_STANDARD_DIRS'][$class];
|
||||
$this->testsDir = $GLOBALS['PHP_CODESNIFFER_TEST_DIRS'][$class];
|
||||
|
||||
}//end setUp()
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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 Config();
|
||||
$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';
|
||||
if (file_exists($fixedFile) === true) {
|
||||
$diff = $phpcsFile->fixer->generateDiff($fixedFile);
|
||||
if (trim($diff) !== '') {
|
||||
$filename = basename($testFile);
|
||||
$fixedFilename = basename($fixedFile);
|
||||
$failureMessages[] = "Fixed version of $filename does not match expected version in $fixedFilename; the diff is\n$diff";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
return;
|
||||
|
||||
}//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
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
<?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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests\Standards;
|
||||
|
||||
use PHP_CodeSniffer\Util\Standards;
|
||||
use PHP_CodeSniffer\Autoload;
|
||||
use PHPUnit\TextUI\TestRunner;
|
||||
use PHPUnit\Framework\TestSuite;
|
||||
|
||||
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');
|
||||
|
||||
$isInstalled = !is_file(__DIR__.'/../../autoload.php');
|
||||
|
||||
// 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 the test is running PEAR installed, the built-in standards
|
||||
// are split into different directories; one for the sniffs and
|
||||
// a different file system location for tests.
|
||||
if ($isInstalled === true && is_dir(dirname($details['path']).DIRECTORY_SEPARATOR.'Generic') === true) {
|
||||
$testPath = realpath(__DIR__.'/../../src/Standards/'.$standard);
|
||||
} else {
|
||||
$testPath = $details['path'];
|
||||
}
|
||||
|
||||
if (in_array($standard, $ignoreTestsForStandards, true) === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$testsDir = $testPath.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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite;
|
||||
use PHPUnit\Framework\TestResult;
|
||||
|
||||
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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
namespace PHP_CodeSniffer\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite;
|
||||
use PHPUnit\Framework\TestResult;
|
||||
|
||||
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): TestResult
|
||||
{
|
||||
$result = parent::run($result);
|
||||
printPHPCodeSnifferTestOutput();
|
||||
return $result;
|
||||
|
||||
}//end run()
|
||||
|
||||
|
||||
}//end class
|
||||
@@ -0,0 +1,91 @@
|
||||
<?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/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
||||
*/
|
||||
|
||||
if (defined('PHP_CODESNIFFER_IN_TESTS') === false) {
|
||||
define('PHP_CODESNIFFER_IN_TESTS', true);
|
||||
}
|
||||
|
||||
if (defined('PHP_CODESNIFFER_CBF') === false) {
|
||||
define('PHP_CODESNIFFER_CBF', false);
|
||||
}
|
||||
|
||||
if (defined('PHP_CODESNIFFER_VERBOSITY') === false) {
|
||||
define('PHP_CODESNIFFER_VERBOSITY', 0);
|
||||
}
|
||||
|
||||
if (is_file(__DIR__.'/../autoload.php') === true) {
|
||||
include_once __DIR__.'/../autoload.php';
|
||||
} else {
|
||||
include_once 'PHP/CodeSniffer/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');
|
||||
}
|
||||
|
||||
// Determine whether this is a PEAR install or not.
|
||||
$GLOBALS['PHP_CODESNIFFER_PEAR'] = false;
|
||||
|
||||
if (is_file(__DIR__.'/../autoload.php') === false) {
|
||||
$GLOBALS['PHP_CODESNIFFER_PEAR'] = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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