基础代码
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
<?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\Autoloader;
|
||||
|
||||
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 = \PHP_CodeSniffer\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 = \PHP_CodeSniffer\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 = \PHP_CodeSniffer\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 = \PHP_CodeSniffer\Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad);
|
||||
$this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className);
|
||||
|
||||
}//end testUnordered()
|
||||
|
||||
|
||||
}//end class
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
|
||||
class A {}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
|
||||
require 'A.inc';
|
||||
class B extends A {}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
namespace PHP_CodeSniffer\Tests\Core\Autoloader;
|
||||
require 'B.inc';
|
||||
class C extends B {}
|
||||
@@ -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 {}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
<?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;
|
||||
|
||||
/* testArrowFunctionReturnValue */
|
||||
fn(): array => [a($a, $b)];
|
||||
|
||||
/* testArrowFunctionAsArgument */
|
||||
$foo = foo(
|
||||
fn() => bar()
|
||||
);
|
||||
|
||||
/* testArrowFunctionWithArrayAsArgument */
|
||||
$foo = foo(
|
||||
fn() => [$row[0], $row[3]]
|
||||
);
|
||||
|
||||
return 0;
|
||||
@@ -0,0 +1,240 @@
|
||||
<?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()
|
||||
|
||||
|
||||
}//end class
|
||||
+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 {}
|
||||
+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
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?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 {}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
<?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]);
|
||||
$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',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataImplementedInterface()
|
||||
|
||||
|
||||
}//end class
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
<?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;
|
||||
}
|
||||
+554
@@ -0,0 +1,554 @@
|
||||
<?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,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testVarType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => false,
|
||||
'type' => '?int',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPublic */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPublicType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => 'string',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testProtected */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testProtectedType */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => 'bool',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPrivate */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPrivateType */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => 'array',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testStatic */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testStaticType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => true,
|
||||
'type' => '?string',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testStaticVar */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testVarStatic */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPublicStatic */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testProtectedStatic */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPrivateStatic */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPublicStaticWithDocblock */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testProtectedStaticWithDocblock */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPrivateStaticWithDocblock */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupType 1 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => 'float',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupType 2 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => 'float',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupNullableType 1 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '?string',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupNullableType 2 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '?string',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNoPrefix */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => false,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupProtectedStatic 1 */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupProtectedStatic 2 */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupProtectedStatic 3 */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 1 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 2 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 3 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 4 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 5 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 6 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testGroupPrivate 7 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMessyNullableType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '?array',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNamespaceType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '\MyNamespace\MyClass',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNullableNamespaceType 1 */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '?ClassName',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNullableNamespaceType 2 */',
|
||||
[
|
||||
'scope' => 'protected',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '?Folder\ClassName',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testMultilineNamespaceType */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '\MyNamespace\MyClass\Foo',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPropertyAfterMethod */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testInterfaceProperty */',
|
||||
[],
|
||||
],
|
||||
[
|
||||
'/* testNestedProperty 1 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNestedProperty 2 */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8MixedTypeHint */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => true,
|
||||
'type' => 'miXed',
|
||||
'nullable_type' => false,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testPHP8MixedTypeHintNullable */',
|
||||
[
|
||||
'scope' => 'private',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '?mixed',
|
||||
'nullable_type' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* testNamespaceOperatorTypeHint */',
|
||||
[
|
||||
'scope' => 'public',
|
||||
'scope_specified' => true,
|
||||
'is_static' => false,
|
||||
'type' => '?namespace\Name',
|
||||
'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 */'],
|
||||
];
|
||||
|
||||
}//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
|
||||
@@ -0,0 +1,43 @@
|
||||
<?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) {}
|
||||
+361
@@ -0,0 +1,361 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the \PHP_CodeSniffer\Files\File:getMethodParameters 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 GetMethodParametersTest extends AbstractMethodUnitTest
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Verify pass-by-reference parsing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPassByReference()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var',
|
||||
'content' => '&$var',
|
||||
'pass_by_reference' => true,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPassByReference()
|
||||
|
||||
|
||||
/**
|
||||
* Verify array hint parsing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrayHint()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var',
|
||||
'content' => 'array $var',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => 'array',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testArrayHint()
|
||||
|
||||
|
||||
/**
|
||||
* Verify type hint parsing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTypeHint()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var1',
|
||||
'content' => 'foo $var1',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => 'foo',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$expected[1] = [
|
||||
'name' => '$var2',
|
||||
'content' => 'bar $var2',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => 'bar',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testTypeHint()
|
||||
|
||||
|
||||
/**
|
||||
* Verify self type hint parsing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSelfTypeHint()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var',
|
||||
'content' => 'self $var',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => 'self',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testSelfTypeHint()
|
||||
|
||||
|
||||
/**
|
||||
* Verify nullable type hint parsing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNullableTypeHint()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var1',
|
||||
'content' => '?int $var1',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '?int',
|
||||
'nullable_type' => true,
|
||||
];
|
||||
|
||||
$expected[1] = [
|
||||
'name' => '$var2',
|
||||
'content' => '?\bar $var2',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '?\bar',
|
||||
'nullable_type' => true,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testNullableTypeHint()
|
||||
|
||||
|
||||
/**
|
||||
* Verify variable.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testVariable()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var',
|
||||
'content' => '$var',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testVariable()
|
||||
|
||||
|
||||
/**
|
||||
* Verify default value parsing with a single function param.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSingleDefaultValue()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var1',
|
||||
'content' => '$var1=self::CONSTANT',
|
||||
'default' => 'self::CONSTANT',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testSingleDefaultValue()
|
||||
|
||||
|
||||
/**
|
||||
* Verify default value parsing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDefaultValues()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var1',
|
||||
'content' => '$var1=1',
|
||||
'default' => '1',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
$expected[1] = [
|
||||
'name' => '$var2',
|
||||
'content' => "\$var2='value'",
|
||||
'default' => "'value'",
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testDefaultValues()
|
||||
|
||||
|
||||
/**
|
||||
* Verify "bitwise and" in default value !== pass-by-reference.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBitwiseAndConstantExpressionDefaultValue()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$a',
|
||||
'content' => '$a = 10 & 20',
|
||||
'default' => '10 & 20',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testBitwiseAndConstantExpressionDefaultValue()
|
||||
|
||||
|
||||
/**
|
||||
* Verify that arrow functions are supported.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrowFunction()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$a',
|
||||
'content' => 'int $a',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => 'int',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$expected[1] = [
|
||||
'name' => '$b',
|
||||
'content' => '...$b',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => true,
|
||||
'type_hint' => '',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 mixed type declaration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8MixedTypeHint()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var1',
|
||||
'content' => 'mixed &...$var1',
|
||||
'pass_by_reference' => true,
|
||||
'variable_length' => true,
|
||||
'type_hint' => 'mixed',
|
||||
'nullable_type' => false,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8MixedTypeHint()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of PHP8 mixed type declaration with nullability.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPHP8MixedTypeHintNullable()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var1',
|
||||
'content' => '?Mixed $var1',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '?Mixed',
|
||||
'nullable_type' => true,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testPHP8MixedTypeHintNullable()
|
||||
|
||||
|
||||
/**
|
||||
* Verify recognition of type declarations using the namespace operator.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNamespaceOperatorTypeHint()
|
||||
{
|
||||
$expected = [];
|
||||
$expected[0] = [
|
||||
'name' => '$var1',
|
||||
'content' => '?namespace\Name $var1',
|
||||
'pass_by_reference' => false,
|
||||
'variable_length' => false,
|
||||
'type_hint' => '?namespace\Name',
|
||||
'nullable_type' => true,
|
||||
];
|
||||
|
||||
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
|
||||
|
||||
}//end testNamespaceOperatorTypeHint()
|
||||
|
||||
|
||||
/**
|
||||
* Test helper.
|
||||
*
|
||||
* @param string $commentString The comment which preceeds the test.
|
||||
* @param array $expected The expected function output.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function getMethodParametersTestHelper($commentString, $expected)
|
||||
{
|
||||
$function = $this->getTargetToken($commentString, [T_FUNCTION, T_FN]);
|
||||
$found = self::$phpcsFile->getMethodParameters($function);
|
||||
|
||||
$this->assertArraySubset($expected, $found, true);
|
||||
|
||||
}//end getMethodParametersTestHelper()
|
||||
|
||||
|
||||
}//end class
|
||||
@@ -0,0 +1,85 @@
|
||||
<?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 {}
|
||||
+496
@@ -0,0 +1,496 @@
|
||||
<?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()
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -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 myFunc($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) {};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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>
|
||||
+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',
|
||||
);
|
||||
+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
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
<?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;
|
||||
|
||||
/* 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);
|
||||
|
||||
$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,
|
||||
];
|
||||
|
||||
/* 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;
|
||||
|
||||
/* testTernary */
|
||||
$fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b';
|
||||
|
||||
/* 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);
|
||||
|
||||
/* testLiveCoding */
|
||||
// Intentional parse error. This has to be the last test in the file.
|
||||
$fn = fn
|
||||
+749
@@ -0,0 +1,749 @@
|
||||
<?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()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
foreach (['/* testStandard */', '/* testMixedCase */'] as $comment) {
|
||||
$token = $this->getTargetToken($comment, T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 12), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 12), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 12), 'Closer scope closer is not the semicolon token');
|
||||
}
|
||||
|
||||
}//end testSimple()
|
||||
|
||||
|
||||
/**
|
||||
* Test whitespace inside arrow function definitions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testWhitespace()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testWhitespace */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 6), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 13), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 6), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 13), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 6), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 13), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//end testWhitespace()
|
||||
|
||||
|
||||
/**
|
||||
* Test comments inside arrow function definitions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testComment()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testComment */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 8), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 15), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 8), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 15), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 8), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 15), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//end testComment()
|
||||
|
||||
|
||||
/**
|
||||
* Test heredocs inside arrow function definitions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHeredoc()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testHeredoc */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 4), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 9), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 4), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 9), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 4), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 9), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//end testHeredoc()
|
||||
|
||||
|
||||
/**
|
||||
* Test nested arrow functions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedOuter()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testNestedOuter */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 25), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 25), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 25), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//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);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 16), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 16), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token - 4), 'Closer scope opener is not the arrow token of the "outer" arrow function (shared scope closer)');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 16), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//end testNestedInner()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that call functions.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFunctionCall()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testFunctionCall */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 17), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 17), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 17), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//end testFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that are included in chained calls.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testChainedFunctionCall()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testChainedFunctionCall */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 12), 'Scope closer is not the bracket token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 12), 'Opener scope closer is not the bracket token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 12), 'Closer scope closer is not the bracket token');
|
||||
|
||||
}//end testChainedFunctionCall()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that are used as function arguments.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testFunctionArgument()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testFunctionArgument */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 8), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 15), 'Scope closer is not the comma token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 8), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 15), 'Opener scope closer is not the comma token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 8), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 15), 'Closer scope closer is not the comma token');
|
||||
|
||||
}//end testFunctionArgument()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that use closures.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testClosure()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testClosure */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 60), 'Scope closer is not the comma token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 60), 'Opener scope closer is not the comma token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 60), 'Closer scope closer is not the comma token');
|
||||
|
||||
}//end testClosure()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions with a return type.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReturnType()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testReturnType */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 11), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 18), 'Scope closer is not the comma token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 11), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 18), 'Opener scope closer is not the comma token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 11), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 18), 'Closer scope closer is not the comma token');
|
||||
|
||||
}//end testReturnType()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that return a reference.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReference()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testReference */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 6), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 9), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 6), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 9), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 6), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 9), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//end testReference()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that are grouped by parenthesis.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGrouped()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testGrouped */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 8), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 8), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 8), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//end testGrouped()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that are used as array values.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrayValue()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testArrayValue */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 4), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 9), 'Scope closer is not the comma token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 4), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 9), 'Opener scope closer is not the comma token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 4), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 9), 'Closer scope closer is not the comma token');
|
||||
|
||||
}//end testArrayValue()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that use the yield keyword.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testYield()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testYield */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 14), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 14), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 14), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//end testYield()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow functions that use nullable namespace types.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNullableNamespace()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testNullableNamespace */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 15), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 18), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 15), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 18), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 15), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 18), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//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()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testNamespaceOperatorInTypes */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 16), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 19), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 16), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 19), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 16), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 19), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//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);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 11), "Scope opener is not the arrow token (for $marker)");
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 14), "Scope closer is not the semicolon token(for $marker)");
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 11), "Opener scope opener is not the arrow token(for $marker)");
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 14), "Opener scope closer is not the semicolon token(for $marker)");
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 11), "Closer scope opener is not the arrow token(for $marker)");
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 14), "Closer scope closer is not the semicolon token(for $marker)");
|
||||
}
|
||||
|
||||
}//end testKeywordReturnTypes()
|
||||
|
||||
|
||||
/**
|
||||
* 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->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 40), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 40), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 40), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
$token = $this->getTargetToken('/* testTernaryThen */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 8), 'Scope opener for THEN is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 12), 'Scope closer for THEN is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 8), 'Opener scope opener for THEN is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 12), 'Opener scope closer for THEN is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 8), 'Closer scope opener for THEN is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 12), 'Closer scope closer for THEN is not the semicolon token');
|
||||
|
||||
$token = $this->getTargetToken('/* testTernaryElse */', T_FN);
|
||||
$this->backfillHelper($token, true);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 8), 'Scope opener for ELSE is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 11), 'Scope closer for ELSE is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 8), 'Opener scope opener for ELSE is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 11), 'Opener scope closer for ELSE is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token - 24), 'Closer scope opener for ELSE is not the arrow token of the "outer" arrow function (shared scope closer)');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 11), 'Closer scope closer for ELSE is not the semicolon token');
|
||||
|
||||
}//end testTernary()
|
||||
|
||||
|
||||
/**
|
||||
* Test arrow function nested within a method declaration.
|
||||
*
|
||||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedInMethod()
|
||||
{
|
||||
$tokens = self::$phpcsFile->getTokens();
|
||||
|
||||
$token = $this->getTargetToken('/* testNestedInMethod */', T_FN);
|
||||
$this->backfillHelper($token);
|
||||
|
||||
$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$token]['scope_closer'], ($token + 17), 'Scope closer is not the semicolon token');
|
||||
|
||||
$opener = $tokens[$token]['scope_opener'];
|
||||
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 17), 'Opener scope closer is not the semicolon token');
|
||||
|
||||
$closer = $tokens[$token]['scope_closer'];
|
||||
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
|
||||
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 17), 'Closer scope closer is not the semicolon token');
|
||||
|
||||
}//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 */'],
|
||||
['/* testLiveCoding */'],
|
||||
];
|
||||
|
||||
}//end dataNotAnArrowFunction()
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to check that all token keys are correctly set for T_FN tokens.
|
||||
*
|
||||
* @param string $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');
|
||||
|
||||
$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()
|
||||
|
||||
|
||||
}//end class
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
<?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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/*
|
||||
* Ensure that legitimate calculations are not touched by the backfill.
|
||||
*/
|
||||
|
||||
/* testCalc1 */
|
||||
$a = 667_083 - 11; // Calculation.
|
||||
|
||||
/* test Calc2 */
|
||||
$a = 6.674_08e3 + 11; // Calculation.
|
||||
+380
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests the backfilling of numeric seperators 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 seperators 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' => '/* testIntMoreThanMax */',
|
||||
'type' => $testIntMoreThanMaxType,
|
||||
'value' => '10_223_372_036_854_775_807',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
}//end dataTestBackfill()
|
||||
|
||||
|
||||
/**
|
||||
* Test that numbers using numeric seperators 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',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'/* 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
|
||||
+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
|
||||
Vendored
+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;
|
||||
Vendored
+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
|
||||
@@ -0,0 +1,94 @@
|
||||
<?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];
|
||||
|
||||
/*
|
||||
* 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]);
|
||||
|
||||
/* testLiveCoding */
|
||||
// Intentional parse error. This has to be the last test in the file.
|
||||
$array = [
|
||||
@@ -0,0 +1,131 @@
|
||||
<?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 [
|
||||
['/* testArrayAccess1 */'],
|
||||
['/* testArrayAccess2 */'],
|
||||
['/* testArrayAssignment */'],
|
||||
['/* testFunctionCallDereferencing */'],
|
||||
['/* testMethodCallDereferencing */'],
|
||||
['/* testStaticMethodCallDereferencing */'],
|
||||
['/* testPropertyDereferencing */'],
|
||||
['/* testPropertyDereferencingWithInaccessibleName */'],
|
||||
['/* testStaticPropertyDereferencing */'],
|
||||
['/* testStringDereferencing */'],
|
||||
['/* testStringDereferencingDoubleQuoted */'],
|
||||
['/* testConstantDereferencing */'],
|
||||
['/* testClassConstantDereferencing */'],
|
||||
['/* testMagicConstantDereferencing */'],
|
||||
['/* testArrayAccessCurlyBraces */'],
|
||||
['/* testArrayLiteralDereferencing */'],
|
||||
['/* testShortArrayLiteralDereferencing */'],
|
||||
['/* testClassMemberDereferencingOnInstantiation1 */'],
|
||||
['/* testClassMemberDereferencingOnInstantiation2 */'],
|
||||
['/* testClassMemberDereferencingOnClone */'],
|
||||
['/* testNullsafeMethodCallDereferencing */'],
|
||||
['/* 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 [
|
||||
['/* testShortArrayDeclarationEmpty */'],
|
||||
['/* testShortArrayDeclarationWithOneValue */'],
|
||||
['/* testShortArrayDeclarationWithMultipleValues */'],
|
||||
['/* testShortArrayDeclarationWithDereferencing */'],
|
||||
['/* testShortListDeclaration */'],
|
||||
['/* testNestedListDeclaration */'],
|
||||
['/* testArrayWithinFunctionCall */'],
|
||||
];
|
||||
|
||||
}//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
|
||||
Vendored
+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();
|
||||
Vendored
+1297
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
|
||||
@@ -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
|
||||
@@ -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