Mercurial > hg > isophonics-drupal-site
comparison vendor/nikic/php-parser/test/PhpParser/NodeTraverserTest.php @ 13:5fb285c0d0e3
Update Drupal core to 8.4.7 via Composer. Security update; I *think* we've
been lucky to get away with this so far, as we don't support self-registration
which seems to be used by the so-called "drupalgeddon 2" attack that 8.4.5
was vulnerable to.
author | Chris Cannam |
---|---|
date | Mon, 23 Apr 2018 09:33:26 +0100 |
parents | 4c8ae668cc8c |
children | 129ea1e6d783 |
comparison
equal
deleted
inserted
replaced
12:7a779792577d | 13:5fb285c0d0e3 |
---|---|
1 <?php | 1 <?php declare(strict_types=1); |
2 | 2 |
3 namespace PhpParser; | 3 namespace PhpParser; |
4 | 4 |
5 use PhpParser\Node\Expr; | 5 use PhpParser\Node\Expr; |
6 use PhpParser\Node\Scalar\String_; | 6 use PhpParser\Node\Scalar\String_; |
7 | 7 use PhpParser\NodeVisitor; |
8 class NodeTraverserTest extends \PHPUnit_Framework_TestCase | 8 use PHPUnit\Framework\TestCase; |
9 | |
10 class NodeTraverserTest extends TestCase | |
9 { | 11 { |
10 public function testNonModifying() { | 12 public function testNonModifying() { |
11 $str1Node = new String_('Foo'); | 13 $str1Node = new String_('Foo'); |
12 $str2Node = new String_('Bar'); | 14 $str2Node = new String_('Bar'); |
13 $echoNode = new Node\Stmt\Echo_(array($str1Node, $str2Node)); | 15 $echoNode = new Node\Stmt\Echo_([$str1Node, $str2Node]); |
14 $stmts = array($echoNode); | 16 $stmts = [$echoNode]; |
15 | 17 |
16 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 18 $visitor = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
17 | 19 |
18 $visitor->expects($this->at(0))->method('beforeTraverse')->with($stmts); | 20 $visitor->expects($this->at(0))->method('beforeTraverse')->with($stmts); |
19 $visitor->expects($this->at(1))->method('enterNode')->with($echoNode); | 21 $visitor->expects($this->at(1))->method('enterNode')->with($echoNode); |
20 $visitor->expects($this->at(2))->method('enterNode')->with($str1Node); | 22 $visitor->expects($this->at(2))->method('enterNode')->with($str1Node); |
21 $visitor->expects($this->at(3))->method('leaveNode')->with($str1Node); | 23 $visitor->expects($this->at(3))->method('leaveNode')->with($str1Node); |
34 $str1Node = new String_('Foo'); | 36 $str1Node = new String_('Foo'); |
35 $str2Node = new String_('Bar'); | 37 $str2Node = new String_('Bar'); |
36 $printNode = new Expr\Print_($str1Node); | 38 $printNode = new Expr\Print_($str1Node); |
37 | 39 |
38 // first visitor changes the node, second verifies the change | 40 // first visitor changes the node, second verifies the change |
39 $visitor1 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 41 $visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
40 $visitor2 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 42 $visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
41 | 43 |
42 // replace empty statements with string1 node | 44 // replace empty statements with string1 node |
43 $visitor1->expects($this->at(0))->method('beforeTraverse')->with(array()) | 45 $visitor1->expects($this->at(0))->method('beforeTraverse')->with([]) |
44 ->will($this->returnValue(array($str1Node))); | 46 ->will($this->returnValue([$str1Node])); |
45 $visitor2->expects($this->at(0))->method('beforeTraverse')->with(array($str1Node)); | 47 $visitor2->expects($this->at(0))->method('beforeTraverse')->with([$str1Node]); |
46 | 48 |
47 // replace string1 node with print node | 49 // replace string1 node with print node |
48 $visitor1->expects($this->at(1))->method('enterNode')->with($str1Node) | 50 $visitor1->expects($this->at(1))->method('enterNode')->with($str1Node) |
49 ->will($this->returnValue($printNode)); | 51 ->will($this->returnValue($printNode)); |
50 $visitor2->expects($this->at(1))->method('enterNode')->with($printNode); | 52 $visitor2->expects($this->at(1))->method('enterNode')->with($printNode); |
63 $visitor1->expects($this->at(4))->method('leaveNode')->with($printNode) | 65 $visitor1->expects($this->at(4))->method('leaveNode')->with($printNode) |
64 ->will($this->returnValue($str1Node)); | 66 ->will($this->returnValue($str1Node)); |
65 $visitor2->expects($this->at(4))->method('leaveNode')->with($str1Node); | 67 $visitor2->expects($this->at(4))->method('leaveNode')->with($str1Node); |
66 | 68 |
67 // replace string1 node with empty statements again | 69 // replace string1 node with empty statements again |
68 $visitor1->expects($this->at(5))->method('afterTraverse')->with(array($str1Node)) | 70 $visitor1->expects($this->at(5))->method('afterTraverse')->with([$str1Node]) |
69 ->will($this->returnValue(array())); | 71 ->will($this->returnValue([])); |
70 $visitor2->expects($this->at(5))->method('afterTraverse')->with(array()); | 72 $visitor2->expects($this->at(5))->method('afterTraverse')->with([]); |
71 | 73 |
72 $traverser = new NodeTraverser; | 74 $traverser = new NodeTraverser; |
73 $traverser->addVisitor($visitor1); | 75 $traverser->addVisitor($visitor1); |
74 $traverser->addVisitor($visitor2); | 76 $traverser->addVisitor($visitor2); |
75 | 77 |
76 // as all operations are reversed we end where we start | 78 // as all operations are reversed we end where we start |
77 $this->assertEquals(array(), $traverser->traverse(array())); | 79 $this->assertEquals([], $traverser->traverse([])); |
78 } | 80 } |
79 | 81 |
80 public function testRemove() { | 82 public function testRemove() { |
81 $str1Node = new String_('Foo'); | 83 $str1Node = new String_('Foo'); |
82 $str2Node = new String_('Bar'); | 84 $str2Node = new String_('Bar'); |
83 | 85 |
84 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 86 $visitor = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
85 | 87 |
86 // remove the string1 node, leave the string2 node | 88 // remove the string1 node, leave the string2 node |
87 $visitor->expects($this->at(2))->method('leaveNode')->with($str1Node) | 89 $visitor->expects($this->at(2))->method('leaveNode')->with($str1Node) |
88 ->will($this->returnValue(false)); | 90 ->will($this->returnValue(NodeTraverser::REMOVE_NODE)); |
89 | 91 |
90 $traverser = new NodeTraverser; | 92 $traverser = new NodeTraverser; |
91 $traverser->addVisitor($visitor); | 93 $traverser->addVisitor($visitor); |
92 | 94 |
93 $this->assertEquals(array($str2Node), $traverser->traverse(array($str1Node, $str2Node))); | 95 $this->assertEquals([$str2Node], $traverser->traverse([$str1Node, $str2Node])); |
94 } | 96 } |
95 | 97 |
96 public function testMerge() { | 98 public function testMerge() { |
97 $strStart = new String_('Start'); | 99 $strStart = new String_('Start'); |
98 $strMiddle = new String_('End'); | 100 $strMiddle = new String_('End'); |
99 $strEnd = new String_('Middle'); | 101 $strEnd = new String_('Middle'); |
100 $strR1 = new String_('Replacement 1'); | 102 $strR1 = new String_('Replacement 1'); |
101 $strR2 = new String_('Replacement 2'); | 103 $strR2 = new String_('Replacement 2'); |
102 | 104 |
103 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 105 $visitor = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
104 | 106 |
105 // replace strMiddle with strR1 and strR2 by merge | 107 // replace strMiddle with strR1 and strR2 by merge |
106 $visitor->expects($this->at(4))->method('leaveNode')->with($strMiddle) | 108 $visitor->expects($this->at(4))->method('leaveNode')->with($strMiddle) |
107 ->will($this->returnValue(array($strR1, $strR2))); | 109 ->will($this->returnValue([$strR1, $strR2])); |
108 | 110 |
109 $traverser = new NodeTraverser; | 111 $traverser = new NodeTraverser; |
110 $traverser->addVisitor($visitor); | 112 $traverser->addVisitor($visitor); |
111 | 113 |
112 $this->assertEquals( | 114 $this->assertEquals( |
113 array($strStart, $strR1, $strR2, $strEnd), | 115 [$strStart, $strR1, $strR2, $strEnd], |
114 $traverser->traverse(array($strStart, $strMiddle, $strEnd)) | 116 $traverser->traverse([$strStart, $strMiddle, $strEnd]) |
115 ); | 117 ); |
116 } | 118 } |
117 | 119 |
118 public function testDeepArray() { | 120 /** |
121 * @expectedException \LogicException | |
122 * @expectedExceptionMessage Invalid node structure: Contains nested arrays | |
123 */ | |
124 public function testInvalidDeepArray() { | |
119 $strNode = new String_('Foo'); | 125 $strNode = new String_('Foo'); |
120 $stmts = array(array(array($strNode))); | 126 $stmts = [[[$strNode]]]; |
121 | 127 |
122 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 128 $traverser = new NodeTraverser; |
123 $visitor->expects($this->at(1))->method('enterNode')->with($strNode); | |
124 | |
125 $traverser = new NodeTraverser; | |
126 $traverser->addVisitor($visitor); | |
127 | |
128 $this->assertEquals($stmts, $traverser->traverse($stmts)); | 129 $this->assertEquals($stmts, $traverser->traverse($stmts)); |
129 } | 130 } |
130 | 131 |
131 public function testDontTraverseChildren() { | 132 public function testDontTraverseChildren() { |
132 $strNode = new String_('str'); | 133 $strNode = new String_('str'); |
133 $printNode = new Expr\Print_($strNode); | 134 $printNode = new Expr\Print_($strNode); |
134 $varNode = new Expr\Variable('foo'); | 135 $varNode = new Expr\Variable('foo'); |
135 $mulNode = new Expr\BinaryOp\Mul($varNode, $varNode); | 136 $mulNode = new Expr\BinaryOp\Mul($varNode, $varNode); |
136 $negNode = new Expr\UnaryMinus($mulNode); | 137 $negNode = new Expr\UnaryMinus($mulNode); |
137 $stmts = array($printNode, $negNode); | 138 $stmts = [$printNode, $negNode]; |
138 | 139 |
139 $visitor1 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 140 $visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
140 $visitor2 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 141 $visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
141 | 142 |
142 $visitor1->expects($this->at(1))->method('enterNode')->with($printNode) | 143 $visitor1->expects($this->at(1))->method('enterNode')->with($printNode) |
143 ->will($this->returnValue(NodeTraverser::DONT_TRAVERSE_CHILDREN)); | 144 ->will($this->returnValue(NodeTraverser::DONT_TRAVERSE_CHILDREN)); |
144 $visitor2->expects($this->at(1))->method('enterNode')->with($printNode); | 145 $visitor2->expects($this->at(1))->method('enterNode')->with($printNode); |
145 | 146 |
173 $mulNode = new Expr\BinaryOp\Mul($varNode1, $varNode2); | 174 $mulNode = new Expr\BinaryOp\Mul($varNode1, $varNode2); |
174 $printNode = new Expr\Print_($varNode3); | 175 $printNode = new Expr\Print_($varNode3); |
175 $stmts = [$mulNode, $printNode]; | 176 $stmts = [$mulNode, $printNode]; |
176 | 177 |
177 // From enterNode() with array parent | 178 // From enterNode() with array parent |
178 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 179 $visitor = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
179 $visitor->expects($this->at(1))->method('enterNode')->with($mulNode) | 180 $visitor->expects($this->at(1))->method('enterNode')->with($mulNode) |
180 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); | 181 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); |
181 $visitor->expects($this->at(2))->method('afterTraverse'); | 182 $visitor->expects($this->at(2))->method('afterTraverse'); |
182 $traverser = new NodeTraverser; | 183 $traverser = new NodeTraverser; |
183 $traverser->addVisitor($visitor); | 184 $traverser->addVisitor($visitor); |
184 $this->assertEquals($stmts, $traverser->traverse($stmts)); | 185 $this->assertEquals($stmts, $traverser->traverse($stmts)); |
185 | 186 |
186 // From enterNode with Node parent | 187 // From enterNode with Node parent |
187 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 188 $visitor = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
188 $visitor->expects($this->at(2))->method('enterNode')->with($varNode1) | 189 $visitor->expects($this->at(2))->method('enterNode')->with($varNode1) |
189 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); | 190 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); |
190 $visitor->expects($this->at(3))->method('afterTraverse'); | 191 $visitor->expects($this->at(3))->method('afterTraverse'); |
191 $traverser = new NodeTraverser; | 192 $traverser = new NodeTraverser; |
192 $traverser->addVisitor($visitor); | 193 $traverser->addVisitor($visitor); |
193 $this->assertEquals($stmts, $traverser->traverse($stmts)); | 194 $this->assertEquals($stmts, $traverser->traverse($stmts)); |
194 | 195 |
195 // From leaveNode with Node parent | 196 // From leaveNode with Node parent |
196 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 197 $visitor = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
197 $visitor->expects($this->at(3))->method('leaveNode')->with($varNode1) | 198 $visitor->expects($this->at(3))->method('leaveNode')->with($varNode1) |
198 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); | 199 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); |
199 $visitor->expects($this->at(4))->method('afterTraverse'); | 200 $visitor->expects($this->at(4))->method('afterTraverse'); |
200 $traverser = new NodeTraverser; | 201 $traverser = new NodeTraverser; |
201 $traverser->addVisitor($visitor); | 202 $traverser->addVisitor($visitor); |
202 $this->assertEquals($stmts, $traverser->traverse($stmts)); | 203 $this->assertEquals($stmts, $traverser->traverse($stmts)); |
203 | 204 |
204 // From leaveNode with array parent | 205 // From leaveNode with array parent |
205 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 206 $visitor = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
206 $visitor->expects($this->at(6))->method('leaveNode')->with($mulNode) | 207 $visitor->expects($this->at(6))->method('leaveNode')->with($mulNode) |
207 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); | 208 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); |
208 $visitor->expects($this->at(7))->method('afterTraverse'); | 209 $visitor->expects($this->at(7))->method('afterTraverse'); |
209 $traverser = new NodeTraverser; | 210 $traverser = new NodeTraverser; |
210 $traverser->addVisitor($visitor); | 211 $traverser->addVisitor($visitor); |
211 $this->assertEquals($stmts, $traverser->traverse($stmts)); | 212 $this->assertEquals($stmts, $traverser->traverse($stmts)); |
212 | 213 |
213 // Check that pending array modifications are still carried out | 214 // Check that pending array modifications are still carried out |
214 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 215 $visitor = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
215 $visitor->expects($this->at(6))->method('leaveNode')->with($mulNode) | 216 $visitor->expects($this->at(6))->method('leaveNode')->with($mulNode) |
216 ->will($this->returnValue(NodeTraverser::REMOVE_NODE)); | 217 ->will($this->returnValue(NodeTraverser::REMOVE_NODE)); |
217 $visitor->expects($this->at(7))->method('enterNode')->with($printNode) | 218 $visitor->expects($this->at(7))->method('enterNode')->with($printNode) |
218 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); | 219 ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL)); |
219 $visitor->expects($this->at(8))->method('afterTraverse'); | 220 $visitor->expects($this->at(8))->method('afterTraverse'); |
222 $this->assertEquals([$printNode], $traverser->traverse($stmts)); | 223 $this->assertEquals([$printNode], $traverser->traverse($stmts)); |
223 | 224 |
224 } | 225 } |
225 | 226 |
226 public function testRemovingVisitor() { | 227 public function testRemovingVisitor() { |
227 $visitor1 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 228 $visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
228 $visitor2 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 229 $visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
229 $visitor3 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 230 $visitor3 = $this->getMockBuilder(NodeVisitor::class)->getMock(); |
230 | 231 |
231 $traverser = new NodeTraverser; | 232 $traverser = new NodeTraverser; |
232 $traverser->addVisitor($visitor1); | 233 $traverser->addVisitor($visitor1); |
233 $traverser->addVisitor($visitor2); | 234 $traverser->addVisitor($visitor2); |
234 $traverser->addVisitor($visitor3); | 235 $traverser->addVisitor($visitor3); |
235 | 236 |
236 $preExpected = array($visitor1, $visitor2, $visitor3); | 237 $preExpected = [$visitor1, $visitor2, $visitor3]; |
237 $this->assertAttributeSame($preExpected, 'visitors', $traverser, 'The appropriate visitors have not been added'); | 238 $this->assertAttributeSame($preExpected, 'visitors', $traverser, 'The appropriate visitors have not been added'); |
238 | 239 |
239 $traverser->removeVisitor($visitor2); | 240 $traverser->removeVisitor($visitor2); |
240 | 241 |
241 $postExpected = array(0 => $visitor1, 2 => $visitor3); | 242 $postExpected = [0 => $visitor1, 2 => $visitor3]; |
242 $this->assertAttributeSame($postExpected, 'visitors', $traverser, 'The appropriate visitors are not present after removal'); | 243 $this->assertAttributeSame($postExpected, 'visitors', $traverser, 'The appropriate visitors are not present after removal'); |
243 } | 244 } |
244 | 245 |
245 public function testNoCloneNodes() { | 246 public function testNoCloneNodes() { |
246 $stmts = array(new Node\Stmt\Echo_(array(new String_('Foo'), new String_('Bar')))); | 247 $stmts = [new Node\Stmt\Echo_([new String_('Foo'), new String_('Bar')])]; |
247 | 248 |
248 $traverser = new NodeTraverser; | 249 $traverser = new NodeTraverser; |
249 | 250 |
250 $this->assertSame($stmts, $traverser->traverse($stmts)); | 251 $this->assertSame($stmts, $traverser->traverse($stmts)); |
251 } | 252 } |
252 | 253 |
253 /** | 254 /** |
254 * @expectedException \LogicException | 255 * @dataProvider provideTestInvalidReturn |
255 * @expectedExceptionMessage leaveNode() may only return an array if the parent structure is an array | |
256 */ | 256 */ |
257 public function testReplaceByArrayOnlyAllowedIfParentIsArray() { | 257 public function testInvalidReturn($visitor, $message) { |
258 $stmts = array(new Node\Expr\UnaryMinus(new Node\Scalar\LNumber(42))); | 258 $this->expectException(\LogicException::class); |
259 | 259 $this->expectExceptionMessage($message); |
260 $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock(); | 260 |
261 $visitor->method('leaveNode')->willReturn(array(new Node\Scalar\DNumber(42.0))); | 261 $stmts = [new Node\Stmt\Expression(new Node\Scalar\LNumber(42))]; |
262 | 262 |
263 $traverser = new NodeTraverser(); | 263 $traverser = new NodeTraverser(); |
264 $traverser->addVisitor($visitor); | 264 $traverser->addVisitor($visitor); |
265 $traverser->traverse($stmts); | 265 $traverser->traverse($stmts); |
266 } | 266 } |
267 | |
268 public function provideTestInvalidReturn() { | |
269 $visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock(); | |
270 $visitor1->expects($this->at(1))->method('enterNode') | |
271 ->willReturn('foobar'); | |
272 | |
273 $visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock(); | |
274 $visitor2->expects($this->at(2))->method('enterNode') | |
275 ->willReturn('foobar'); | |
276 | |
277 $visitor3 = $this->getMockBuilder(NodeVisitor::class)->getMock(); | |
278 $visitor3->expects($this->at(3))->method('leaveNode') | |
279 ->willReturn('foobar'); | |
280 | |
281 $visitor4 = $this->getMockBuilder(NodeVisitor::class)->getMock(); | |
282 $visitor4->expects($this->at(4))->method('leaveNode') | |
283 ->willReturn('foobar'); | |
284 | |
285 $visitor5 = $this->getMockBuilder(NodeVisitor::class)->getMock(); | |
286 $visitor5->expects($this->at(3))->method('leaveNode') | |
287 ->willReturn([new Node\Scalar\DNumber(42.0)]); | |
288 | |
289 $visitor6 = $this->getMockBuilder(NodeVisitor::class)->getMock(); | |
290 $visitor6->expects($this->at(4))->method('leaveNode') | |
291 ->willReturn(false); | |
292 | |
293 $visitor7 = $this->getMockBuilder(NodeVisitor::class)->getMock(); | |
294 $visitor7->expects($this->at(1))->method('enterNode') | |
295 ->willReturn(new Node\Scalar\LNumber(42)); | |
296 | |
297 $visitor8 = $this->getMockBuilder(NodeVisitor::class)->getMock(); | |
298 $visitor8->expects($this->at(2))->method('enterNode') | |
299 ->willReturn(new Node\Stmt\Return_()); | |
300 | |
301 return [ | |
302 [$visitor1, 'enterNode() returned invalid value of type string'], | |
303 [$visitor2, 'enterNode() returned invalid value of type string'], | |
304 [$visitor3, 'leaveNode() returned invalid value of type string'], | |
305 [$visitor4, 'leaveNode() returned invalid value of type string'], | |
306 [$visitor5, 'leaveNode() may only return an array if the parent structure is an array'], | |
307 [$visitor6, 'bool(false) return from leaveNode() no longer supported. Return NodeTraverser::REMOVE_NODE instead'], | |
308 [$visitor7, 'Trying to replace statement (Stmt_Expression) with expression (Scalar_LNumber). Are you missing a Stmt_Expression wrapper?'], | |
309 [$visitor8, 'Trying to replace expression (Scalar_LNumber) with statement (Stmt_Return)'], | |
310 ]; | |
311 } | |
267 } | 312 } |