annotate vendor/nikic/php-parser/test/PhpParser/ParserTest.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@13 1 <?php declare(strict_types=1);
Chris@0 2
Chris@0 3 namespace PhpParser;
Chris@0 4
Chris@0 5 use PhpParser\Node\Expr;
Chris@0 6 use PhpParser\Node\Scalar;
Chris@0 7 use PhpParser\Node\Scalar\String_;
Chris@13 8 use PhpParser\Node\Stmt;
Chris@0 9
Chris@17 10 abstract class ParserTest extends \PHPUnit\Framework\TestCase
Chris@0 11 {
Chris@0 12 /** @returns Parser */
Chris@0 13 abstract protected function getParser(Lexer $lexer);
Chris@0 14
Chris@0 15 public function testParserThrowsSyntaxError() {
Chris@17 16 $this->expectException(Error::class);
Chris@17 17 $this->expectExceptionMessage('Syntax error, unexpected EOF on line 1');
Chris@0 18 $parser = $this->getParser(new Lexer());
Chris@0 19 $parser->parse('<?php foo');
Chris@0 20 }
Chris@0 21
Chris@0 22 public function testParserThrowsSpecialError() {
Chris@17 23 $this->expectException(Error::class);
Chris@17 24 $this->expectExceptionMessage('Cannot use foo as self because \'self\' is a special class name on line 1');
Chris@0 25 $parser = $this->getParser(new Lexer());
Chris@0 26 $parser->parse('<?php use foo as self;');
Chris@0 27 }
Chris@0 28
Chris@0 29 public function testParserThrowsLexerError() {
Chris@17 30 $this->expectException(Error::class);
Chris@17 31 $this->expectExceptionMessage('Unterminated comment on line 1');
Chris@0 32 $parser = $this->getParser(new Lexer());
Chris@0 33 $parser->parse('<?php /*');
Chris@0 34 }
Chris@0 35
Chris@0 36 public function testAttributeAssignment() {
Chris@13 37 $lexer = new Lexer([
Chris@13 38 'usedAttributes' => [
Chris@0 39 'comments', 'startLine', 'endLine',
Chris@0 40 'startTokenPos', 'endTokenPos',
Chris@13 41 ]
Chris@13 42 ]);
Chris@0 43
Chris@0 44 $code = <<<'EOC'
Chris@0 45 <?php
Chris@0 46 /** Doc comment */
Chris@0 47 function test($a) {
Chris@0 48 // Line
Chris@0 49 // Comments
Chris@0 50 echo $a;
Chris@0 51 }
Chris@0 52 EOC;
Chris@0 53 $code = canonicalize($code);
Chris@0 54
Chris@0 55 $parser = $this->getParser($lexer);
Chris@0 56 $stmts = $parser->parse($code);
Chris@0 57
Chris@13 58 /** @var Stmt\Function_ $fn */
Chris@0 59 $fn = $stmts[0];
Chris@13 60 $this->assertInstanceOf(Stmt\Function_::class, $fn);
Chris@13 61 $this->assertEquals([
Chris@13 62 'comments' => [
Chris@13 63 new Comment\Doc('/** Doc comment */', 2, 6, 1),
Chris@13 64 ],
Chris@0 65 'startLine' => 3,
Chris@0 66 'endLine' => 7,
Chris@0 67 'startTokenPos' => 3,
Chris@0 68 'endTokenPos' => 21,
Chris@13 69 ], $fn->getAttributes());
Chris@0 70
Chris@0 71 $param = $fn->params[0];
Chris@13 72 $this->assertInstanceOf(Node\Param::class, $param);
Chris@13 73 $this->assertEquals([
Chris@0 74 'startLine' => 3,
Chris@0 75 'endLine' => 3,
Chris@0 76 'startTokenPos' => 7,
Chris@0 77 'endTokenPos' => 7,
Chris@13 78 ], $param->getAttributes());
Chris@0 79
Chris@13 80 /** @var Stmt\Echo_ $echo */
Chris@0 81 $echo = $fn->stmts[0];
Chris@13 82 $this->assertInstanceOf(Stmt\Echo_::class, $echo);
Chris@13 83 $this->assertEquals([
Chris@13 84 'comments' => [
Chris@13 85 new Comment("// Line\n", 4, 49, 12),
Chris@13 86 new Comment("// Comments\n", 5, 61, 14),
Chris@13 87 ],
Chris@0 88 'startLine' => 6,
Chris@0 89 'endLine' => 6,
Chris@0 90 'startTokenPos' => 16,
Chris@0 91 'endTokenPos' => 19,
Chris@13 92 ], $echo->getAttributes());
Chris@0 93
Chris@0 94 /** @var \PhpParser\Node\Expr\Variable $var */
Chris@0 95 $var = $echo->exprs[0];
Chris@13 96 $this->assertInstanceOf(Expr\Variable::class, $var);
Chris@13 97 $this->assertEquals([
Chris@0 98 'startLine' => 6,
Chris@0 99 'endLine' => 6,
Chris@0 100 'startTokenPos' => 18,
Chris@0 101 'endTokenPos' => 18,
Chris@13 102 ], $var->getAttributes());
Chris@0 103 }
Chris@0 104
Chris@0 105 public function testInvalidToken() {
Chris@17 106 $this->expectException(\RangeException::class);
Chris@17 107 $this->expectExceptionMessage('The lexer returned an invalid token (id=999, value=foobar)');
Chris@0 108 $lexer = new InvalidTokenLexer;
Chris@0 109 $parser = $this->getParser($lexer);
Chris@0 110 $parser->parse('dummy');
Chris@0 111 }
Chris@0 112
Chris@0 113 /**
Chris@0 114 * @dataProvider provideTestExtraAttributes
Chris@0 115 */
Chris@0 116 public function testExtraAttributes($code, $expectedAttributes) {
Chris@17 117 $parser = $this->getParser(new Lexer\Emulative);
Chris@0 118 $stmts = $parser->parse("<?php $code;");
Chris@13 119 $node = $stmts[0] instanceof Stmt\Expression ? $stmts[0]->expr : $stmts[0];
Chris@13 120 $attributes = $node->getAttributes();
Chris@0 121 foreach ($expectedAttributes as $name => $value) {
Chris@0 122 $this->assertSame($value, $attributes[$name]);
Chris@0 123 }
Chris@0 124 }
Chris@0 125
Chris@0 126 public function provideTestExtraAttributes() {
Chris@13 127 return [
Chris@13 128 ['0', ['kind' => Scalar\LNumber::KIND_DEC]],
Chris@13 129 ['9', ['kind' => Scalar\LNumber::KIND_DEC]],
Chris@13 130 ['07', ['kind' => Scalar\LNumber::KIND_OCT]],
Chris@13 131 ['0xf', ['kind' => Scalar\LNumber::KIND_HEX]],
Chris@13 132 ['0XF', ['kind' => Scalar\LNumber::KIND_HEX]],
Chris@13 133 ['0b1', ['kind' => Scalar\LNumber::KIND_BIN]],
Chris@13 134 ['0B1', ['kind' => Scalar\LNumber::KIND_BIN]],
Chris@13 135 ['[]', ['kind' => Expr\Array_::KIND_SHORT]],
Chris@13 136 ['array()', ['kind' => Expr\Array_::KIND_LONG]],
Chris@13 137 ["'foo'", ['kind' => String_::KIND_SINGLE_QUOTED]],
Chris@13 138 ["b'foo'", ['kind' => String_::KIND_SINGLE_QUOTED]],
Chris@13 139 ["B'foo'", ['kind' => String_::KIND_SINGLE_QUOTED]],
Chris@13 140 ['"foo"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
Chris@13 141 ['b"foo"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
Chris@13 142 ['B"foo"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
Chris@13 143 ['"foo$bar"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
Chris@13 144 ['b"foo$bar"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
Chris@13 145 ['B"foo$bar"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
Chris@17 146 ["<<<'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 147 ["<<<STR\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 148 ["<<<\"STR\"\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 149 ["b<<<'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 150 ["B<<<'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 151 ["<<< \t 'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 152 ["<<<'\xff'\n\xff\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => "\xff", 'docIndentation' => '']],
Chris@17 153 ["<<<\"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 154 ["b<<<\"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 155 ["B<<<\"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 156 ["<<< \t \"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR', 'docIndentation' => '']],
Chris@17 157 ["<<<STR\n STR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR', 'docIndentation' => ' ']],
Chris@17 158 ["<<<STR\n\tSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR', 'docIndentation' => "\t"]],
Chris@17 159 ["<<<'STR'\n Foo\n STR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR', 'docIndentation' => ' ']],
Chris@13 160 ["die", ['kind' => Expr\Exit_::KIND_DIE]],
Chris@13 161 ["die('done')", ['kind' => Expr\Exit_::KIND_DIE]],
Chris@13 162 ["exit", ['kind' => Expr\Exit_::KIND_EXIT]],
Chris@13 163 ["exit(1)", ['kind' => Expr\Exit_::KIND_EXIT]],
Chris@13 164 ["?>Foo", ['hasLeadingNewline' => false]],
Chris@13 165 ["?>\nFoo", ['hasLeadingNewline' => true]],
Chris@13 166 ["namespace Foo;", ['kind' => Stmt\Namespace_::KIND_SEMICOLON]],
Chris@13 167 ["namespace Foo {}", ['kind' => Stmt\Namespace_::KIND_BRACED]],
Chris@13 168 ["namespace {}", ['kind' => Stmt\Namespace_::KIND_BRACED]],
Chris@17 169 ["(float) 5.0", ['kind' => Expr\Cast\Double::KIND_FLOAT]],
Chris@17 170 ["(double) 5.0", ['kind' => Expr\Cast\Double::KIND_DOUBLE]],
Chris@17 171 ["(real) 5.0", ['kind' => Expr\Cast\Double::KIND_REAL]],
Chris@17 172 [" ( REAL ) 5.0", ['kind' => Expr\Cast\Double::KIND_REAL]],
Chris@13 173 ];
Chris@0 174 }
Chris@0 175 }
Chris@0 176
Chris@13 177 class InvalidTokenLexer extends Lexer
Chris@13 178 {
Chris@13 179 public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) : int {
Chris@0 180 $value = 'foobar';
Chris@0 181 return 999;
Chris@0 182 }
Chris@0 183 }