* @copyright 2025 PHPCSStandards and contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP;
use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase;
/**
* Tests the support of PHP 8.4 asymmetric visibility.
*
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
*/
final class BackfillAsymmetricVisibilityTest extends AbstractTokenizerTestCase
{
/**
* Test that the asymmetric visibility keywords are tokenized as such.
*
* @param string $testMarker The comment which prefaces the target token in the test file.
* @param string $testType The expected token type
* @param string $testContent The token content to look for
*
* @dataProvider dataAsymmetricVisibility
*
* @return void
*/
public function testAsymmetricVisibility($testMarker, $testType, $testContent)
{
$tokens = $this->phpcsFile->getTokens();
$target = $this->getTargetToken(
$testMarker,
[
T_PUBLIC_SET,
T_PROTECTED_SET,
T_PRIVATE_SET,
]
);
$tokenArray = $tokens[$target];
$this->assertSame(
$testType,
$tokenArray['type'],
'Token tokenized as '.$tokenArray['type'].' (type)'
);
$this->assertSame(
constant($testType),
$tokenArray['code'],
'Token tokenized as '.$tokenArray['type'].' (code)'
);
$this->assertSame(
$testContent,
$tokenArray['content'],
'Token tokenized as '.$tokenArray['type'].' (content)'
);
}//end testAsymmetricVisibility()
/**
* Data provider.
*
* @see testAsymmetricVisibility()
*
* @return array>
*/
public static function dataAsymmetricVisibility()
{
return [
// Normal property declarations.
'property, public set, no read visibility, lowercase' => [
'testMarker' => '/* testPublicSetProperty */',
'testType' => 'T_PUBLIC_SET',
'testContent' => 'public(set)',
],
'property, public set, no read visibility, uppercase' => [
'testMarker' => '/* testPublicSetPropertyUC */',
'testType' => 'T_PUBLIC_SET',
'testContent' => 'PUBLIC(SET)',
],
'property, public set, has read visibility, lowercase' => [
'testMarker' => '/* testPublicPublicSetProperty */',
'testType' => 'T_PUBLIC_SET',
'testContent' => 'public(set)',
],
'property, public set, has read visibility, uppercase' => [
'testMarker' => '/* testPublicPublicSetPropertyUC */',
'testType' => 'T_PUBLIC_SET',
'testContent' => 'PUBLIC(SET)',
],
'property, protected set, no read visibility, lowercase' => [
'testMarker' => '/* testProtectedSetProperty */',
'testType' => 'T_PROTECTED_SET',
'testContent' => 'protected(set)',
],
'property, protected set, no read visibility, uppercase' => [
'testMarker' => '/* testProtectedSetPropertyUC */',
'testType' => 'T_PROTECTED_SET',
'testContent' => 'PROTECTED(SET)',
],
'property, protected set, has read visibility, lowercase' => [
'testMarker' => '/* testPublicProtectedSetProperty */',
'testType' => 'T_PROTECTED_SET',
'testContent' => 'protected(set)',
],
'property, protected set, has read visibility, uppercase' => [
'testMarker' => '/* testPublicProtectedSetPropertyUC */',
'testType' => 'T_PROTECTED_SET',
'testContent' => 'PROTECTED(SET)',
],
'property, private set, no read visibility, lowercase' => [
'testMarker' => '/* testPrivateSetProperty */',
'testType' => 'T_PRIVATE_SET',
'testContent' => 'private(set)',
],
'property, private set, no read visibility, uppercase' => [
'testMarker' => '/* testPrivateSetPropertyUC */',
'testType' => 'T_PRIVATE_SET',
'testContent' => 'PRIVATE(SET)',
],
'property, private set, has read visibility, lowercase' => [
'testMarker' => '/* testPublicPrivateSetProperty */',
'testType' => 'T_PRIVATE_SET',
'testContent' => 'private(set)',
],
'property, private set, has read visibility, uppercase' => [
'testMarker' => '/* testPublicPrivateSetPropertyUC */',
'testType' => 'T_PRIVATE_SET',
'testContent' => 'PRIVATE(SET)',
],
// Constructor property promotion.
'promotion, public set, no read visibility, lowercase' => [
'testMarker' => '/* testPublicSetCPP */',
'testType' => 'T_PUBLIC_SET',
'testContent' => 'public(set)',
],
'promotion, public set, no read visibility, uppercase' => [
'testMarker' => '/* testPublicSetCPPUC */',
'testType' => 'T_PUBLIC_SET',
'testContent' => 'PUBLIC(SET)',
],
'promotion, public set, has read visibility, lowercase' => [
'testMarker' => '/* testPublicPublicSetCPP */',
'testType' => 'T_PUBLIC_SET',
'testContent' => 'public(set)',
],
'promotion, public set, has read visibility, uppercase' => [
'testMarker' => '/* testPublicPublicSetCPPUC */',
'testType' => 'T_PUBLIC_SET',
'testContent' => 'PUBLIC(SET)',
],
'promotion, protected set, no read visibility, lowercase' => [
'testMarker' => '/* testProtectedSetCPP */',
'testType' => 'T_PROTECTED_SET',
'testContent' => 'protected(set)',
],
'promotion, protected set, no read visibility, uppercase' => [
'testMarker' => '/* testProtectedSetCPPUC */',
'testType' => 'T_PROTECTED_SET',
'testContent' => 'PROTECTED(SET)',
],
'promotion, protected set, has read visibility, lowercase' => [
'testMarker' => '/* testPublicProtectedSetCPP */',
'testType' => 'T_PROTECTED_SET',
'testContent' => 'protected(set)',
],
'promotion, protected set, has read visibility, uppercase' => [
'testMarker' => '/* testPublicProtectedSetCPPUC */',
'testType' => 'T_PROTECTED_SET',
'testContent' => 'PROTECTED(SET)',
],
'promotion, private set, no read visibility, lowercase' => [
'testMarker' => '/* testPrivateSetCPP */',
'testType' => 'T_PRIVATE_SET',
'testContent' => 'private(set)',
],
'promotion, private set, no read visibility, uppercase' => [
'testMarker' => '/* testPrivateSetCPPUC */',
'testType' => 'T_PRIVATE_SET',
'testContent' => 'PRIVATE(SET)',
],
'promotion, private set, has read visibility, lowercase' => [
'testMarker' => '/* testPublicPrivateSetCPP */',
'testType' => 'T_PRIVATE_SET',
'testContent' => 'private(set)',
],
'promotion, private set, has read visibility, uppercase' => [
'testMarker' => '/* testPublicPrivateSetCPPUC */',
'testType' => 'T_PRIVATE_SET',
'testContent' => 'PRIVATE(SET)',
],
];
}//end dataAsymmetricVisibility()
/**
* Test that things that are not asymmetric visibility keywords are not
* tokenized as such.
*
* @param string $testMarker The comment which prefaces the target token in the test file.
* @param string $testType The expected token type
* @param string $testContent The token content to look for
*
* @dataProvider dataNotAsymmetricVisibility
*
* @return void
*/
public function testNotAsymmetricVisibility($testMarker, $testType, $testContent)
{
$tokens = $this->phpcsFile->getTokens();
$target = $this->getTargetToken(
$testMarker,
[constant($testType)],
$testContent
);
$tokenArray = $tokens[$target];
$this->assertSame(
$testType,
$tokenArray['type'],
'Token tokenized as '.$tokenArray['type'].' (type)'
);
$this->assertSame(
constant($testType),
$tokenArray['code'],
'Token tokenized as '.$tokenArray['type'].' (code)'
);
}//end testNotAsymmetricVisibility()
/**
* Data provider.
*
* @see testNotAsymmetricVisibility()
*
* @return array>
*/
public static function dataNotAsymmetricVisibility()
{
return [
'property, invalid case 1' => [
'testMarker' => '/* testInvalidUnsetProperty */',
'testType' => 'T_PUBLIC',
'testContent' => 'public',
],
'property, invalid case 2' => [
'testMarker' => '/* testInvalidSpaceProperty */',
'testType' => 'T_PUBLIC',
'testContent' => 'public',
],
'property, invalid case 3' => [
'testMarker' => '/* testInvalidCommentProperty */',
'testType' => 'T_PROTECTED',
'testContent' => 'protected',
],
'property, invalid case 4' => [
'testMarker' => '/* testInvalidGetProperty */',
'testType' => 'T_PRIVATE',
'testContent' => 'private',
],
'property, invalid case 5' => [
'testMarker' => '/* testInvalidNoParenProperty */',
'testType' => 'T_PRIVATE',
'testContent' => 'private',
],
// Constructor property promotion.
'promotion, invalid case 1' => [
'testMarker' => '/* testInvalidUnsetCPP */',
'testType' => 'T_PUBLIC',
'testContent' => 'public',
],
'promotion, invalid case 2' => [
'testMarker' => '/* testInvalidSpaceCPP */',
'testType' => 'T_PUBLIC',
'testContent' => 'public',
],
'promotion, invalid case 3' => [
'testMarker' => '/* testInvalidCommentCPP */',
'testType' => 'T_PROTECTED',
'testContent' => 'protected',
],
'promotion, invalid case 4' => [
'testMarker' => '/* testInvalidGetCPP */',
'testType' => 'T_PRIVATE',
'testContent' => 'private',
],
'promotion, invalid case 5' => [
'testMarker' => '/* testInvalidNoParenCPP */',
'testType' => 'T_PRIVATE',
'testContent' => 'private',
],
// Context sensitivitiy.
'protected as function name' => [
'testMarker' => '/* testProtectedFunctionName */',
'testType' => 'T_STRING',
'testContent' => 'protected',
],
'public as function name' => [
'testMarker' => '/* testPublicFunctionName */',
'testType' => 'T_STRING',
'testContent' => 'public',
],
'set as parameter type' => [
'testMarker' => '/* testSetParameterType */',
'testType' => 'T_STRING',
'testContent' => 'Set',
],
// Live coding.
'live coding' => [
'testMarker' => '/* testLiveCoding */',
'testType' => 'T_PRIVATE',
'testContent' => 'private',
],
];
}//end dataNotAsymmetricVisibility()
}//end class