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