LexerTest   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 298
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 2
Bugs 2 Features 0
Metric Value
wmc 14
c 2
b 2
f 0
lcom 1
cbo 5
dl 0
loc 298
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getLexer() 0 4 1
A testError() 0 17 3
A provideTestError() 0 8 1
A testLex() 0 13 2
B provideTestLex() 0 184 1
A testHandleHaltCompiler() 0 11 2
A provideTestHaltCompiler() 0 10 1
A testHandleHaltCompilerError() 0 9 2
A testGetTokens() 0 17 1
1
<?php
2
3
namespace PhpSchool\PSXTest;
4
5
use PhpParser\Comment;
6
use PhpParser\Error;
7
use PhpParser\Parser\Tokens;
8
use PhpSchool\PSX\Lexer;
9
use PHPUnit_Framework_TestCase;
10
11
/**
12
 * Class LexerTest
13
 * @package PhpSchool\PSXTest
14
 * @author Aydin Hassan <[email protected]>
15
 */
16
class LexerTest extends PHPUnit_Framework_TestCase
17
{
18
    /* To allow overwriting in parent class */
19
    protected function getLexer(array $options = array())
20
    {
21
        return new Lexer($options);
22
    }
23
24
    /**
25
     * @dataProvider provideTestError
26
     */
27
    public function testError($code, $message)
28
    {
29
        if (defined('HHVM_VERSION')) {
30
            $this->markTestSkipped('HHVM does not throw warnings from token_get_all()');
31
        }
32
33
        $lexer = $this->getLexer();
34
        try {
35
            $lexer->startLexing($code);
36
        } catch (Error $e) {
37
            $this->assertSame($message, $e->getMessage());
38
39
            return;
40
        }
41
42
        $this->fail('Expected PhpParser\Error');
43
    }
44
45
    public function provideTestError()
46
    {
47
        return array(
48
            array('<?php /*', 'Unterminated comment on line 1'),
49
            array('<?php ' . "\1", 'Unexpected character "' . "\1" . '" (ASCII 1) on unknown line'),
50
            array('<?php ' . "\0", 'Unexpected null byte on unknown line'),
51
        );
52
    }
53
54
    /**
55
     * @dataProvider provideTestLex
56
     */
57
    public function testLex($code, $options, $tokens)
58
    {
59
        $lexer = $this->getLexer($options);
60
        $lexer->startLexing($code);
61
        while ($id = $lexer->getNextToken($value, $startAttributes, $endAttributes)) {
62
            $token = array_shift($tokens);
63
64
            $this->assertSame($token[0], $id);
65
            $this->assertSame($token[1], $value);
66
            $this->assertEquals($token[2], $startAttributes);
67
            $this->assertEquals($token[3], $endAttributes);
68
        }
69
    }
70
71
    public function provideTestLex()
72
    {
73
        return array(
74
            // tests conversion of closing PHP tag and drop of whitespace and opening tags
75
            array(
76
                '<?php tokens ?>plaintext',
77
                array(),
78
                array(
79
                    array(
80
                        Tokens::T_STRING, 'tokens',
81
                        array('startLine' => 1), array('endLine' => 1)
82
                    ),
83
                    array(
84
                        ord(';'), '?>',
85
                        array('startLine' => 1), array('endLine' => 1)
86
                    ),
87
                    array(
88
                        Tokens::T_INLINE_HTML, 'plaintext',
89
                        array('startLine' => 1), array('endLine' => 1)
90
                    ),
91
                )
92
            ),
93
            // tests line numbers
94
            array(
95
                '<?php' . "\n" . '$ token /** doc' . "\n" . 'comment */ $',
96
                array(),
97
                array(
98
                    array(
99
                        ord('$'), '$',
100
                        array('startLine' => 2), array('endLine' => 2)
101
                    ),
102
                    array(
103
                        Tokens::T_STRING, 'token',
104
                        array('startLine' => 2), array('endLine' => 2)
105
                    ),
106
                    array(
107
                        ord('$'), '$',
108
                        array(
109
                            'startLine' => 3,
110
                            'comments' => array(new Comment\Doc('/** doc' . "\n" . 'comment */', 2))
111
                        ),
112
                        array('endLine' => 3)
113
                    ),
114
                )
115
            ),
116
            // tests comment extraction
117
            array(
118
                '<?php /* comment */ // comment' . "\n" . '/** docComment 1 *//** docComment 2 */ token',
119
                array(),
120
                array(
121
                    array(
122
                        Tokens::T_STRING, 'token',
123
                        array(
124
                            'startLine' => 2,
125
                            'comments' => array(
126
                                new Comment('/* comment */', 1),
127
                                new Comment('// comment' . "\n", 1),
128
                                new Comment\Doc('/** docComment 1 */', 2),
129
                                new Comment\Doc('/** docComment 2 */', 2),
130
                            ),
131
                        ),
132
                        array('endLine' => 2)
133
                    ),
134
                )
135
            ),
136
            // tests differing start and end line
137
            array(
138
                '<?php "foo' . "\n" . 'bar"',
139
                array(),
140
                array(
141
                    array(
142
                        Tokens::T_CONSTANT_ENCAPSED_STRING, '"foo' . "\n" . 'bar"',
143
                        array('startLine' => 1), array('endLine' => 2, 'originalValue' => "\"foo\nbar\"")
144
                    ),
145
                )
146
            ),
147
            // tests exact file offsets
148
            array(
149
                '<?php "a";' . "\n" . '// foo' . "\n" . '"b";',
150
                array('usedAttributes' => array('startFilePos', 'endFilePos')),
151
                array(
152
                    array(
153
                        Tokens::T_CONSTANT_ENCAPSED_STRING, '"a"',
154
                        array('startFilePos' => 6), array('endFilePos' => 8, 'originalValue' => '"a"')
155
                    ),
156
                    array(
157
                        ord(';'), ';',
158
                        array('startFilePos' => 9), array('endFilePos' => 9)
159
                    ),
160
                    array(
161
                        Tokens::T_CONSTANT_ENCAPSED_STRING, '"b"',
162
                        array('startFilePos' => 18), array('endFilePos' => 20, 'originalValue' => '"b"')
163
                    ),
164
                    array(
165
                        ord(';'), ';',
166
                        array('startFilePos' => 21), array('endFilePos' => 21)
167
                    ),
168
                )
169
            ),
170
            // tests token offsets
171
            array(
172
                '<?php "a";' . "\n" . '// foo' . "\n" . '"b";',
173
                array('usedAttributes' => array('startTokenPos', 'endTokenPos')),
174
                array(
175
                    array(
176
                        Tokens::T_CONSTANT_ENCAPSED_STRING, '"a"',
177
                        array('startTokenPos' => 1), array('endTokenPos' => 1, 'originalValue' => '"a"')
178
                    ),
179
                    array(
180
                        ord(';'), ';',
181
                        array('startTokenPos' => 2), array('endTokenPos' => 2)
182
                    ),
183
                    array(
184
                        Tokens::T_CONSTANT_ENCAPSED_STRING, '"b"',
185
                        array('startTokenPos' => 5), array('endTokenPos' => 5, 'originalValue' => '"b"')
186
                    ),
187
                    array(
188
                        ord(';'), ';',
189
                        array('startTokenPos' => 6), array('endTokenPos' => 6)
190
                    ),
191
                )
192
            ),
193
            // tests all attributes being disabled
194
            array(
195
                '<?php /* foo */ $bar;',
196
                array('usedAttributes' => array()),
197
                array(
198
                    array(
199
                        Tokens::T_VARIABLE, '$bar',
200
                        array(), array()
201
                    ),
202
                    array(
203
                        ord(';'), ';',
204
                        array(), array()
205
                    )
206
                )
207
            ),
208
            // test traditional array syntax
209
            array(
210
                '<?php $bar = array();',
211
                array('usedAttributes' => array()),
212
                array(
213
                    array(
214
                        Tokens::T_VARIABLE, '$bar',
215
                        array(), array()
216
                    ),
217
                    array(
218
                        ord('='), '=',
219
                        array(), array()
220
                    ),
221
                    array(
222
                        Tokens::T_ARRAY, 'array',
223
                        array('traditionalArray' => true), array()
224
                    ),
225
                    array(
226
                        ord('('), '(',
227
                        array(), array()
228
                    ),
229
                    array(
230
                        ord(')'), ')',
231
                        array(), array()
232
                    ),
233
                    array(
234
                        ord(';'), ';',
235
                        array(), array()
236
                    )
237
                )
238
            ),
239
            array(
240
                '<?php die;',
241
                array('usedAttributes' => array()),
242
                array(
243
                    array(
244
                        Tokens::T_EXIT, 'die',
245
                        array('isDie' => true), array()
246
                    ),
247
                    array(
248
                        ord(';'), ';',
249
                        array(), array()
250
                    )
251
                )
252
            )
253
        );
254
    }
255
256
    /**
257
     * @dataProvider provideTestHaltCompiler
258
     */
259
    public function testHandleHaltCompiler($code, $remaining)
260
    {
261
        $lexer = $this->getLexer();
262
        $lexer->startLexing($code);
263
264
        while (Tokens::T_HALT_COMPILER !== $lexer->getNextToken()) {
0 ignored issues
show
Unused Code introduced by
This while loop is empty and can be removed.

This check looks for while loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
265
        }
266
267
        $this->assertSame($remaining, $lexer->handleHaltCompiler());
268
        $this->assertSame(0, $lexer->getNextToken());
269
    }
270
271
    public function provideTestHaltCompiler()
272
    {
273
        return array(
274
            array('<?php ... __halt_compiler();Remaining Text', 'Remaining Text'),
275
            array('<?php ... __halt_compiler ( ) ;Remaining Text', 'Remaining Text'),
276
            array('<?php ... __halt_compiler() ?>Remaining Text', 'Remaining Text'),
277
            //array('<?php ... __halt_compiler();' . "\0", "\0"),
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
278
            //array('<?php ... __halt_compiler /* */ ( ) ;Remaining Text', 'Remaining Text'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
88% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
279
        );
280
    }
281
282
    /**
283
     * @expectedException \PhpParser\Error
284
     * @expectedExceptionMessage __HALT_COMPILER must be followed by "();"
285
     */
286
    public function testHandleHaltCompilerError()
287
    {
288
        $lexer = $this->getLexer();
289
        $lexer->startLexing('<?php ... __halt_compiler invalid ();');
290
291
        while (Tokens::T_HALT_COMPILER !== $lexer->getNextToken()) {
0 ignored issues
show
Unused Code introduced by
This while loop is empty and can be removed.

This check looks for while loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
292
        }
293
        $lexer->handleHaltCompiler();
294
    }
295
296
    public function testGetTokens()
297
    {
298
        $code = '<?php "a";' . "\n" . '// foo' . "\n" . '"b";';
299
        $expectedTokens = array(
300
            array(T_OPEN_TAG, '<?php ', 1),
301
            array(T_CONSTANT_ENCAPSED_STRING, '"a"', 1),
302
            ';',
303
            array(T_WHITESPACE, "\n", 1),
304
            array(T_COMMENT, '// foo' . "\n", 2),
305
            array(T_CONSTANT_ENCAPSED_STRING, '"b"', 3),
306
            ';',
307
        );
308
309
        $lexer = $this->getLexer();
310
        $lexer->startLexing($code);
311
        $this->assertSame($expectedTokens, $lexer->getTokens());
312
    }
313
}
314