* @copyright 2024 PHPCSStandards and contributors * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer\PHP; use PHP_CodeSniffer\Tests\Core\Tokenizer\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; /** * Tests that simple tokens are assigned the correct token type and code. * * @covers PHP_CodeSniffer\Tokenizers\PHP::resolveSimpleToken */ final class ResolveSimpleTokenTest extends AbstractTokenizerTestCase { /** * Clear the "resolved tokens" cache before running this test as otherwise the code * under test may not be run during the test. * * @beforeClass * * @return void */ public static function clearTokenCache() { parent::clearResolvedTokensCache(); }//end clearTokenCache() /** * Verify tokenization of parentheses, square brackets, curly brackets and a switch colon. * * @return void */ public function testBracesAndColon() { $expectedSequence = [ T_OPEN_PARENTHESIS, T_VARIABLE, T_OPEN_SQUARE_BRACKET, T_LNUMBER, T_CLOSE_SQUARE_BRACKET, T_CLOSE_PARENTHESIS, T_OPEN_CURLY_BRACKET, T_CASE, T_STRING, T_COLON, T_BREAK, T_SEMICOLON, T_CLOSE_CURLY_BRACKET, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_SWITCH); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testBracesAndColon() /** * Verify tokenization of colon after named parameter. * * @return void */ public function testNamedParamColon() { $expectedSequence = [ T_OPEN_PARENTHESIS, T_PARAM_NAME, T_COLON, T_VARIABLE, T_CLOSE_PARENTHESIS, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_STRING); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testNamedParamColon() /** * Verify tokenization of colon for a return type. * * @return void */ public function testReturnTypeColon() { $expectedSequence = [ T_EQUAL, T_CLOSURE, T_OPEN_PARENTHESIS, T_CLOSE_PARENTHESIS, T_COLON, T_STRING, T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testReturnTypeColon() /** * Verify tokenization of a concatenation operator. * * @return void */ public function testConcat() { $expectedSequence = [ T_STRING_CONCAT, T_VARIABLE, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_CONSTANT_ENCAPSED_STRING); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testConcat() /** * Verify tokenization of simple math operators. * * @return void */ public function testSimpleMathTokens() { $expectedSequence = [ T_EQUAL, T_LNUMBER, T_MULTIPLY, T_LNUMBER, T_DIVIDE, T_LNUMBER, T_PLUS, T_LNUMBER, T_MINUS, T_LNUMBER, T_MODULUS, T_LNUMBER, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testSimpleMathTokens() /** * Verify tokenization of unary plus/minus operators. * * @return void */ public function testUnaryPlusMinus() { $expectedSequence = [ T_EQUAL, T_PLUS, T_LNUMBER, T_DIVIDE, T_MINUS, T_LNUMBER, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testUnaryPlusMinus() /** * Verify tokenization of bitwise operator tokens. * * @return void */ public function testBitwiseTokens() { $expectedSequence = [ T_EQUAL, T_STRING, T_BITWISE_XOR, T_STRING, T_BITWISE_AND, T_STRING, T_BITWISE_OR, T_STRING, T_BITWISE_NOT, T_STRING, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testBitwiseTokens() /** * Verify tokenization of bitwise operator tokens. * * @return void */ public function testBitwiseOrInCatch() { $expectedSequence = [ T_OPEN_PARENTHESIS, T_STRING, T_BITWISE_OR, T_STRING, T_VARIABLE, T_CLOSE_PARENTHESIS, T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_CATCH); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testBitwiseOrInCatch() /** * Verify tokenization of a less than operator. * * @return void */ public function testLessThan() { $expectedSequence = [ T_LESS_THAN, T_VARIABLE, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_LNUMBER); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testLessThan() /** * Verify tokenization of a greater than operator. * * @return void */ public function testGreaterThan() { $expectedSequence = [ T_GREATER_THAN, T_VARIABLE, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_LNUMBER); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testGreaterThan() /** * Verify tokenization of a boolean not operator. * * @return void */ public function testBooleanNot() { $expectedSequence = [ T_BOOLEAN_NOT, T_VARIABLE, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testBooleanNot() /** * Verify tokenization of commas. * * @return void */ public function testComma() { $expectedSequence = [ T_COMMA, T_VARIABLE, T_COMMA, T_VARIABLE, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testComma() /** * Verify tokenization of the silence operator. * * @return void */ public function testAsperand() { $expectedSequence = [ T_ASPERAND, T_STRING, T_OPEN_PARENTHESIS, T_CLOSE_PARENTHESIS, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testAsperand() /** * Verify tokenization of the dollar token and curlies for a variable variable. * * @return void */ public function testDollarAndCurlies() { $expectedSequence = [ T_DOLLAR, T_OPEN_CURLY_BRACKET, T_VARIABLE, T_CLOSE_CURLY_BRACKET, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_ECHO); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testDollarAndCurlies() /** * Verify tokenization of the backtick operator. * * @return void */ public function testBacktick() { $expectedSequence = [ T_BACKTICK, T_ENCAPSED_AND_WHITESPACE, T_BACKTICK, T_SEMICOLON, ]; $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); $this->checkTokenSequence(($target + 1), $expectedSequence); }//end testBacktick() /** * Test helper. Check a token sequence complies with an expected token sequence. * * @param int $startPtr The position in the file to start checking from. * @param array $expectedSequence The consecutive token constants to expect. * * @return void */ private function checkTokenSequence($startPtr, array $expectedSequence) { $tokens = $this->phpcsFile->getTokens(); $sequenceKey = 0; $sequenceCount = count($expectedSequence); for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++) { if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { // Ignore whitespace and comments, not interested in the tokenization of those for these tests. continue; } $expectedTokenName = Tokens::tokenName($expectedSequence[$sequenceKey]); $this->assertSame( $expectedSequence[$sequenceKey], $tokens[$i]['code'], 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedTokenName.' (code)' ); $this->assertSame( $expectedTokenName, $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedTokenName.' (type)' ); ++$sequenceKey; }//end for }//end checkTokenSequence() }//end class