LexerTest.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php declare(strict_types=1);
  2. namespace PhpParser;
  3. require __DIR__ . '/../../lib/PhpParser/compatibility_tokens.php';
  4. class LexerTest extends \PHPUnit\Framework\TestCase {
  5. /* To allow overwriting in parent class */
  6. protected function getLexer() {
  7. return new Lexer();
  8. }
  9. /**
  10. * @dataProvider provideTestError
  11. */
  12. public function testError($code, $messages): void {
  13. if (defined('HHVM_VERSION')) {
  14. $this->markTestSkipped('HHVM does not throw warnings from token_get_all()');
  15. }
  16. $errorHandler = new ErrorHandler\Collecting();
  17. $lexer = $this->getLexer();
  18. $lexer->tokenize($code, $errorHandler);
  19. $errors = $errorHandler->getErrors();
  20. $this->assertCount(count($messages), $errors);
  21. for ($i = 0; $i < count($messages); $i++) {
  22. $this->assertSame($messages[$i], $errors[$i]->getMessageWithColumnInfo($code));
  23. }
  24. }
  25. public static function provideTestError() {
  26. return [
  27. ["<?php /*", ["Unterminated comment from 1:7 to 1:9"]],
  28. ["<?php /*\n", ["Unterminated comment from 1:7 to 2:1"]],
  29. ["<?php \1", ["Unexpected character \"\1\" (ASCII 1) from 1:7 to 1:7"]],
  30. ["<?php \0", ["Unexpected null byte from 1:7 to 1:7"]],
  31. // Error with potentially emulated token
  32. ["<?php ?? \0", ["Unexpected null byte from 1:10 to 1:10"]],
  33. ["<?php\n\0\1 foo /* bar", [
  34. "Unexpected null byte from 2:1 to 2:1",
  35. "Unexpected character \"\1\" (ASCII 1) from 2:2 to 2:2",
  36. "Unterminated comment from 2:8 to 2:14"
  37. ]],
  38. ];
  39. }
  40. public function testDefaultErrorHandler(): void {
  41. $this->expectException(Error::class);
  42. $this->expectExceptionMessage('Unterminated comment on line 1');
  43. $lexer = $this->getLexer();
  44. $lexer->tokenize("<?php readonly /*");
  45. }
  46. /**
  47. * @dataProvider provideTestLex
  48. */
  49. public function testLex($code, $expectedTokens): void {
  50. $lexer = $this->getLexer();
  51. $tokens = $lexer->tokenize($code);
  52. foreach ($tokens as $token) {
  53. if ($token->id === 0 || $token->isIgnorable()) {
  54. continue;
  55. }
  56. $expectedToken = array_shift($expectedTokens);
  57. $this->assertSame($expectedToken[0], $token->id);
  58. $this->assertSame($expectedToken[1], $token->text);
  59. }
  60. }
  61. public static function provideTestLex() {
  62. return [
  63. // tests PHP 8 T_NAME_* emulation
  64. [
  65. '<?php Foo\Bar \Foo\Bar namespace\Foo\Bar Foo\Bar\\',
  66. [
  67. [\T_NAME_QUALIFIED, 'Foo\Bar'],
  68. [\T_NAME_FULLY_QUALIFIED, '\Foo\Bar'],
  69. [\T_NAME_RELATIVE, 'namespace\Foo\Bar'],
  70. [\T_NAME_QUALIFIED, 'Foo\Bar'],
  71. [\T_NS_SEPARATOR, '\\'],
  72. ]
  73. ],
  74. // tests PHP 8 T_NAME_* emulation with reserved keywords
  75. [
  76. '<?php fn\use \fn\use namespace\fn\use fn\use\\',
  77. [
  78. [\T_NAME_QUALIFIED, 'fn\use'],
  79. [\T_NAME_FULLY_QUALIFIED, '\fn\use'],
  80. [\T_NAME_RELATIVE, 'namespace\fn\use'],
  81. [\T_NAME_QUALIFIED, 'fn\use'],
  82. [\T_NS_SEPARATOR, '\\'],
  83. ]
  84. ],
  85. ];
  86. }
  87. public function testGetTokens(): void {
  88. $code = '<?php "a";' . "\n" . '// foo' . "\n" . '// bar' . "\n\n" . '"b";';
  89. $expectedTokens = [
  90. new Token(T_OPEN_TAG, '<?php ', 1, 0),
  91. new Token(T_CONSTANT_ENCAPSED_STRING, '"a"', 1, 6),
  92. new Token(\ord(';'), ';', 1, 9),
  93. new Token(T_WHITESPACE, "\n", 1, 10),
  94. new Token(T_COMMENT, '// foo', 2, 11),
  95. new Token(T_WHITESPACE, "\n", 2, 17),
  96. new Token(T_COMMENT, '// bar', 3, 18),
  97. new Token(T_WHITESPACE, "\n\n", 3, 24),
  98. new Token(T_CONSTANT_ENCAPSED_STRING, '"b"', 5, 26),
  99. new Token(\ord(';'), ';', 5, 29),
  100. new Token(0, "\0", 5, 30),
  101. ];
  102. $lexer = $this->getLexer();
  103. $this->assertEquals($expectedTokens, $lexer->tokenize($code));
  104. }
  105. }