Skip to content

Commit

Permalink
Tokenizer/PHP: add more tests for default keyword and double arrow
Browse files Browse the repository at this point in the history
In particular, this adds tests where the `default` keyword is not used as the keyword and should be tokenized as `T_STRING`.
  • Loading branch information
jrfnl committed Mar 25, 2021
1 parent 2bd19c2 commit 14ac7eb
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 90 deletions.
102 changes: 102 additions & 0 deletions tests/Core/Tokenizer/DefaultKeywordTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,105 @@ function switchWithDefaultInMatch() {
}
};
}

function shortArrayWithConstantKey() {
$arr = [
/* testClassConstantAsShortArrayKey */
SomeClass::DEFAULT => 1,
/* testClassPropertyAsShortArrayKey */
SomeClass->DEFAULT => 1,
/* testNamespacedConstantAsShortArrayKey */
// Intentional parse error PHP < 8.0. Reserved keyword used as namespaced constant.
SomeNamespace\DEFAULT => 1,
/* testFQNGlobalConstantAsShortArrayKey */
// Intentional parse error in PHP < 8.0. Reserved keyword used as global constant.
\DEFAULT => 1,
];
}

function longArrayWithConstantKey() {
$arr = array(
/* testClassConstantAsLongArrayKey */
SomeClass::DEFAULT => 1,
);
}

function yieldWithConstantKey() {
/* testClassConstantAsYieldKey */
yield SomeClass::DEFAULT => 1;
}

function longArrayWithConstantKeyNestedInMatch() {
return match($x) {
/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */
DEFAULT => array(
/* testClassConstantAsLongArrayKeyNestedInMatch */
SomeClass::DEFAULT => match($x) {
/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */
DEFAULT => array(
/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */
SomeClass::DEFAULT => 1,
),
},
),
};
}

function shortArrayWithConstantKeyNestedInMatch() {
return match($x) {
/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */
DEFAULT => [
/* testClassConstantAsShortArrayKeyNestedInMatch */
SomeClass::DEFAULT => match($x) {
/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */
DEFAULT => [
/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */
SomeClass::DEFAULT => 1,
],
},
],
};
}


function longArrayWithConstantKeyWithNestedMatch() {
return array(
/* testClassConstantAsLongArrayKeyWithNestedMatch */
SomeClass::DEFAULT => match($x) {
/* testMatchDefaultNestedInLongArray */
DEFAULT => 'foo'
},
);
}

function shortArrayWithConstantKeyWithNestedMatch() {
return [
/* testClassConstantAsShortArrayKeyWithNestedMatch */
SomeClass::DEFAULT => match($x) {
/* testMatchDefaultNestedInShortArray */
DEFAULT => 'foo'
},
];
}

function switchWithConstantNonDefault($i) {
switch ($i) {
/* testClassConstantInSwitchCase */
case SomeClass::DEFAULT:
return 1;

/* testClassPropertyInSwitchCase */
case SomeClass->DEFAULT:
return 2;

/* testNamespacedConstantInSwitchCase */
// Intentional parse error PHP < 8.0. Reserved keyword used as constant.
case SomeNamespace\DEFAULT:
return 2;

/* testNamespaceRelativeConstantInSwitchCase */
// Intentional parse error PHP < 8.0. Reserved keyword used as global constant.
case namespace\DEFAULT:
return 2;
}
}
110 changes: 100 additions & 10 deletions tests/Core/Tokenizer/DefaultKeywordTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,20 @@ class DefaultKeywordTest extends AbstractMethodUnitTest
* Note: Cases and default structures within a match structure do *NOT* get case/default scope
* conditions, in contrast to case and default structures in switch control structures.
*
* @param string $testMarker The comment prefacing the target token.
* @param string $testMarker The comment prefacing the target token.
* @param string $testContent The token content to look for.
*
* @dataProvider dataMatchDefault
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap
*
* @return void
*/
public function testMatchDefault($testMarker)
public function testMatchDefault($testMarker, $testContent='default')
{
$tokens = self::$phpcsFile->getTokens();

$token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT]);
$token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent);
$tokenArray = $tokens[$token];

$this->assertSame(T_MATCH_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (code)');
Expand All @@ -57,11 +58,36 @@ public function testMatchDefault($testMarker)
public function dataMatchDefault()
{
return [
'simple_match_default' => ['/* testSimpleMatchDefault */'],
'match_default_in_switch_case_1' => ['/* testMatchDefaultNestedInSwitchCase1 */'],
'match_default_in_switch_case_2' => ['/* testMatchDefaultNestedInSwitchCase2 */'],
'match_default_in_switch_default' => ['/* testMatchDefaultNestedInSwitchDefault */'],
'match_default_containing_switch' => ['/* testMatchDefault */'],
'simple_match_default' => ['/* testSimpleMatchDefault */'],
'match_default_in_switch_case_1' => ['/* testMatchDefaultNestedInSwitchCase1 */'],
'match_default_in_switch_case_2' => ['/* testMatchDefaultNestedInSwitchCase2 */'],
'match_default_in_switch_default' => ['/* testMatchDefaultNestedInSwitchDefault */'],
'match_default_containing_switch' => ['/* testMatchDefault */'],

'match_default_with_nested_long_array_and_default_key' => [
'/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */',
'DEFAULT',
],
'match_default_with_nested_long_array_and_default_key_2' => [
'/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */',
'DEFAULT',
],
'match_default_with_nested_short_array_and_default_key' => [
'/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */',
'DEFAULT',
],
'match_default_with_nested_short_array_and_default_key_2' => [
'/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */',
'DEFAULT',
],
'match_default_in_long_array' => [
'/* testMatchDefaultNestedInLongArray */',
'DEFAULT',
],
'match_default_in_short_array' => [
'/* testMatchDefaultNestedInShortArray */',
'DEFAULT',
],
];

}//end dataMatchDefault()
Expand All @@ -78,17 +104,18 @@ public function dataMatchDefault()
* @param int $openerOffset The expected offset of the scope opener in relation to the testMarker.
* @param int $closerOffset The expected offset of the scope closer in relation to the testMarker.
* @param int|null $conditionStop The expected offset at which tokens stop having T_DEFAULT as a scope condition.
* @param string $testContent The token content to look for.
*
* @dataProvider dataSwitchDefault
* @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap
*
* @return void
*/
public function testSwitchDefault($testMarker, $openerOffset, $closerOffset, $conditionStop=null)
public function testSwitchDefault($testMarker, $openerOffset, $closerOffset, $conditionStop=null, $testContent='default')
{
$tokens = self::$phpcsFile->getTokens();

$token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT]);
$token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent);
$tokenArray = $tokens[$token];
$expectedScopeOpener = ($token + $openerOffset);
$expectedScopeCloser = ($token + $closerOffset);
Expand Down Expand Up @@ -182,4 +209,67 @@ public function dataSwitchDefault()
}//end dataSwitchDefault()


/**
* Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively
* impact the tokenization of `T_STRING` tokens with the contents 'default' which aren't in
* actual fact the default keyword.
*
* @param string $testMarker The comment prefacing the target token.
* @param string $testContent The token content to look for.
*
* @dataProvider dataNotDefaultKeyword
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
*
* @return void
*/
public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT')
{
$tokens = self::$phpcsFile->getTokens();

$token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent);
$tokenArray = $tokens[$token];

$this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)');
$this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)');

$this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set');
$this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set');
$this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set');

}//end testNotDefaultKeyword()


/**
* Data provider.
*
* @see testNotDefaultKeyword()
*
* @return array
*/
public function dataNotDefaultKeyword()
{
return [
'class-constant-as-short-array-key' => ['/* testClassConstantAsShortArrayKey */'],
'class-property-as-short-array-key' => ['/* testClassPropertyAsShortArrayKey */'],
'namespaced-constant-as-short-array-key' => ['/* testNamespacedConstantAsShortArrayKey */'],
'fqn-global-constant-as-short-array-key' => ['/* testFQNGlobalConstantAsShortArrayKey */'],
'class-constant-as-long-array-key' => ['/* testClassConstantAsLongArrayKey */'],
'class-constant-as-yield-key' => ['/* testClassConstantAsYieldKey */'],

'class-constant-as-long-array-key-nested-in-match' => ['/* testClassConstantAsLongArrayKeyNestedInMatch */'],
'class-constant-as-long-array-key-nested-in-match-2' => ['/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */'],
'class-constant-as-short-array-key-nested-in-match' => ['/* testClassConstantAsShortArrayKeyNestedInMatch */'],
'class-constant-as-short-array-key-nested-in-match-2' => ['/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */'],
'class-constant-as-long-array-key-with-nested-match' => ['/* testClassConstantAsLongArrayKeyWithNestedMatch */'],
'class-constant-as-short-array-key-with-nested-match' => ['/* testClassConstantAsShortArrayKeyWithNestedMatch */'],

'class-constant-in-switch-case' => ['/* testClassConstantInSwitchCase */'],
'class-property-in-switch-case' => ['/* testClassPropertyInSwitchCase */'],
'namespaced-constant-in-switch-case' => ['/* testNamespacedConstantInSwitchCase */'],
'namespace-relative-constant-in-switch-case' => ['/* testNamespaceRelativeConstantInSwitchCase */'],
];

}//end dataNotDefaultKeyword()


}//end class
60 changes: 60 additions & 0 deletions tests/Core/Tokenizer/DoubleArrowTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,63 @@ function matchInShortList() {
/* testMatchArrowInShortListKey */
[match($x) {1 => 1, 2 => 2} /* testShortListArrowWithMatchInKey */ => $a] = $array;
}

function longArrayWithConstantKey() {
$arr = array(
/* testLongArrayArrowWithClassConstantKey */
SomeClass::DEFAULT => 1,
);
}

function shortArrayWithConstantKey() {
$arr = [
/* testShortArrayArrowWithClassConstantKey */
SomeClass::DEFAULT => 1,
];
}

function yieldWithConstantKey() {
/* testYieldArrowWithClassConstantKey */
yield SomeClass::DEFAULT => 1;
}

function longArrayWithConstantKeyNestedInMatch() {
return match($x) {
/* testMatchArrowWithNestedLongArrayWithClassConstantKey */
default => array(
/* testLongArrayArrowWithClassConstantKeyNestedInMatch */
SomeClass::DEFAULT => 1,
),
};
}

function shortArrayWithConstantKeyNestedInMatch() {
return match($x) {
/* testMatchArrowWithNestedShortArrayWithClassConstantKey */
default => [
/* testShortArrayArrowWithClassConstantKeyNestedInMatch */
SomeClass::DEFAULT => 1,
],
};
}


function longArrayWithConstantKeyWithNestedMatch() {
return array(
/* testLongArrayArrowWithClassConstantKeyWithNestedMatch */
SomeClass::DEFAULT => match($x) {
/* testMatchArrowNestedInLongArrayWithClassConstantKey */
default => 'foo'
},
);
}

function shortArrayWithConstantKeyWithNestedMatch() {
return [
/* testShortArrayArrowWithClassConstantKeyWithNestedMatch */
SomeClass::DEFAULT => match($x) {
/* testMatchArrowNestedInShortArrayWithClassConstantKey */
default => 'foo'
},
];
}
Loading

0 comments on commit 14ac7eb

Please sign in to comment.