Security update for Core, with self-updated composer
[yaffs-website] / vendor / nikic / php-parser / test / PhpParser / NodeTraverserTest.php
1 <?php
2
3 namespace PhpParser;
4
5 use PhpParser\Node\Expr;
6 use PhpParser\Node\Scalar\String_;
7
8 class NodeTraverserTest extends \PHPUnit_Framework_TestCase
9 {
10     public function testNonModifying() {
11         $str1Node = new String_('Foo');
12         $str2Node = new String_('Bar');
13         $echoNode = new Node\Stmt\Echo_(array($str1Node, $str2Node));
14         $stmts    = array($echoNode);
15
16         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
17
18         $visitor->expects($this->at(0))->method('beforeTraverse')->with($stmts);
19         $visitor->expects($this->at(1))->method('enterNode')->with($echoNode);
20         $visitor->expects($this->at(2))->method('enterNode')->with($str1Node);
21         $visitor->expects($this->at(3))->method('leaveNode')->with($str1Node);
22         $visitor->expects($this->at(4))->method('enterNode')->with($str2Node);
23         $visitor->expects($this->at(5))->method('leaveNode')->with($str2Node);
24         $visitor->expects($this->at(6))->method('leaveNode')->with($echoNode);
25         $visitor->expects($this->at(7))->method('afterTraverse')->with($stmts);
26
27         $traverser = new NodeTraverser;
28         $traverser->addVisitor($visitor);
29
30         $this->assertEquals($stmts, $traverser->traverse($stmts));
31     }
32
33     public function testModifying() {
34         $str1Node  = new String_('Foo');
35         $str2Node  = new String_('Bar');
36         $printNode = new Expr\Print_($str1Node);
37
38         // first visitor changes the node, second verifies the change
39         $visitor1 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
40         $visitor2 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
41
42         // replace empty statements with string1 node
43         $visitor1->expects($this->at(0))->method('beforeTraverse')->with(array())
44                  ->will($this->returnValue(array($str1Node)));
45         $visitor2->expects($this->at(0))->method('beforeTraverse')->with(array($str1Node));
46
47         // replace string1 node with print node
48         $visitor1->expects($this->at(1))->method('enterNode')->with($str1Node)
49                  ->will($this->returnValue($printNode));
50         $visitor2->expects($this->at(1))->method('enterNode')->with($printNode);
51
52         // replace string1 node with string2 node
53         $visitor1->expects($this->at(2))->method('enterNode')->with($str1Node)
54                  ->will($this->returnValue($str2Node));
55         $visitor2->expects($this->at(2))->method('enterNode')->with($str2Node);
56
57         // replace string2 node with string1 node again
58         $visitor1->expects($this->at(3))->method('leaveNode')->with($str2Node)
59                  ->will($this->returnValue($str1Node));
60         $visitor2->expects($this->at(3))->method('leaveNode')->with($str1Node);
61
62         // replace print node with string1 node again
63         $visitor1->expects($this->at(4))->method('leaveNode')->with($printNode)
64                  ->will($this->returnValue($str1Node));
65         $visitor2->expects($this->at(4))->method('leaveNode')->with($str1Node);
66
67         // replace string1 node with empty statements again
68         $visitor1->expects($this->at(5))->method('afterTraverse')->with(array($str1Node))
69                  ->will($this->returnValue(array()));
70         $visitor2->expects($this->at(5))->method('afterTraverse')->with(array());
71
72         $traverser = new NodeTraverser;
73         $traverser->addVisitor($visitor1);
74         $traverser->addVisitor($visitor2);
75
76         // as all operations are reversed we end where we start
77         $this->assertEquals(array(), $traverser->traverse(array()));
78     }
79
80     public function testRemove() {
81         $str1Node = new String_('Foo');
82         $str2Node = new String_('Bar');
83
84         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
85
86         // remove the string1 node, leave the string2 node
87         $visitor->expects($this->at(2))->method('leaveNode')->with($str1Node)
88                 ->will($this->returnValue(false));
89
90         $traverser = new NodeTraverser;
91         $traverser->addVisitor($visitor);
92
93         $this->assertEquals(array($str2Node), $traverser->traverse(array($str1Node, $str2Node)));
94     }
95
96     public function testMerge() {
97         $strStart  = new String_('Start');
98         $strMiddle = new String_('End');
99         $strEnd    = new String_('Middle');
100         $strR1     = new String_('Replacement 1');
101         $strR2     = new String_('Replacement 2');
102
103         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
104
105         // replace strMiddle with strR1 and strR2 by merge
106         $visitor->expects($this->at(4))->method('leaveNode')->with($strMiddle)
107                 ->will($this->returnValue(array($strR1, $strR2)));
108
109         $traverser = new NodeTraverser;
110         $traverser->addVisitor($visitor);
111
112         $this->assertEquals(
113             array($strStart, $strR1, $strR2, $strEnd),
114             $traverser->traverse(array($strStart, $strMiddle, $strEnd))
115         );
116     }
117
118     public function testDeepArray() {
119         $strNode = new String_('Foo');
120         $stmts = array(array(array($strNode)));
121
122         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
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     }
130
131     public function testDontTraverseChildren() {
132         $strNode = new String_('str');
133         $printNode = new Expr\Print_($strNode);
134         $varNode = new Expr\Variable('foo');
135         $mulNode = new Expr\BinaryOp\Mul($varNode, $varNode);
136         $negNode = new Expr\UnaryMinus($mulNode);
137         $stmts = array($printNode, $negNode);
138
139         $visitor1 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
140         $visitor2 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
141
142         $visitor1->expects($this->at(1))->method('enterNode')->with($printNode)
143             ->will($this->returnValue(NodeTraverser::DONT_TRAVERSE_CHILDREN));
144         $visitor2->expects($this->at(1))->method('enterNode')->with($printNode);
145
146         $visitor1->expects($this->at(2))->method('leaveNode')->with($printNode);
147         $visitor2->expects($this->at(2))->method('leaveNode')->with($printNode);
148
149         $visitor1->expects($this->at(3))->method('enterNode')->with($negNode);
150         $visitor2->expects($this->at(3))->method('enterNode')->with($negNode);
151
152         $visitor1->expects($this->at(4))->method('enterNode')->with($mulNode);
153         $visitor2->expects($this->at(4))->method('enterNode')->with($mulNode)
154             ->will($this->returnValue(NodeTraverser::DONT_TRAVERSE_CHILDREN));
155
156         $visitor1->expects($this->at(5))->method('leaveNode')->with($mulNode);
157         $visitor2->expects($this->at(5))->method('leaveNode')->with($mulNode);
158
159         $visitor1->expects($this->at(6))->method('leaveNode')->with($negNode);
160         $visitor2->expects($this->at(6))->method('leaveNode')->with($negNode);
161
162         $traverser = new NodeTraverser;
163         $traverser->addVisitor($visitor1);
164         $traverser->addVisitor($visitor2);
165
166         $this->assertEquals($stmts, $traverser->traverse($stmts));
167     }
168
169     public function testStopTraversal() {
170         $varNode1 = new Expr\Variable('a');
171         $varNode2 = new Expr\Variable('b');
172         $varNode3 = new Expr\Variable('c');
173         $mulNode = new Expr\BinaryOp\Mul($varNode1, $varNode2);
174         $printNode = new Expr\Print_($varNode3);
175         $stmts = [$mulNode, $printNode];
176
177         // From enterNode() with array parent
178         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
179         $visitor->expects($this->at(1))->method('enterNode')->with($mulNode)
180             ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
181         $visitor->expects($this->at(2))->method('afterTraverse');
182         $traverser = new NodeTraverser;
183         $traverser->addVisitor($visitor);
184         $this->assertEquals($stmts, $traverser->traverse($stmts));
185
186         // From enterNode with Node parent
187         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
188         $visitor->expects($this->at(2))->method('enterNode')->with($varNode1)
189             ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
190         $visitor->expects($this->at(3))->method('afterTraverse');
191         $traverser = new NodeTraverser;
192         $traverser->addVisitor($visitor);
193         $this->assertEquals($stmts, $traverser->traverse($stmts));
194
195         // From leaveNode with Node parent
196         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
197         $visitor->expects($this->at(3))->method('leaveNode')->with($varNode1)
198             ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
199         $visitor->expects($this->at(4))->method('afterTraverse');
200         $traverser = new NodeTraverser;
201         $traverser->addVisitor($visitor);
202         $this->assertEquals($stmts, $traverser->traverse($stmts));
203
204         // From leaveNode with array parent
205         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
206         $visitor->expects($this->at(6))->method('leaveNode')->with($mulNode)
207             ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
208         $visitor->expects($this->at(7))->method('afterTraverse');
209         $traverser = new NodeTraverser;
210         $traverser->addVisitor($visitor);
211         $this->assertEquals($stmts, $traverser->traverse($stmts));
212
213         // Check that pending array modifications are still carried out
214         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
215         $visitor->expects($this->at(6))->method('leaveNode')->with($mulNode)
216             ->will($this->returnValue(NodeTraverser::REMOVE_NODE));
217         $visitor->expects($this->at(7))->method('enterNode')->with($printNode)
218             ->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
219         $visitor->expects($this->at(8))->method('afterTraverse');
220         $traverser = new NodeTraverser;
221         $traverser->addVisitor($visitor);
222         $this->assertEquals([$printNode], $traverser->traverse($stmts));
223
224     }
225
226     public function testRemovingVisitor() {
227         $visitor1 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
228         $visitor2 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
229         $visitor3 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
230
231         $traverser = new NodeTraverser;
232         $traverser->addVisitor($visitor1);
233         $traverser->addVisitor($visitor2);
234         $traverser->addVisitor($visitor3);
235
236         $preExpected = array($visitor1, $visitor2, $visitor3);
237         $this->assertAttributeSame($preExpected, 'visitors', $traverser, 'The appropriate visitors have not been added');
238
239         $traverser->removeVisitor($visitor2);
240
241         $postExpected = array(0 => $visitor1, 2 => $visitor3);
242         $this->assertAttributeSame($postExpected, 'visitors', $traverser, 'The appropriate visitors are not present after removal');
243     }
244
245     public function testNoCloneNodes() {
246         $stmts = array(new Node\Stmt\Echo_(array(new String_('Foo'), new String_('Bar'))));
247
248         $traverser = new NodeTraverser;
249
250         $this->assertSame($stmts, $traverser->traverse($stmts));
251     }
252
253     /**
254      * @expectedException \LogicException
255      * @expectedExceptionMessage leaveNode() may only return an array if the parent structure is an array
256      */
257     public function testReplaceByArrayOnlyAllowedIfParentIsArray() {
258         $stmts = array(new Node\Expr\UnaryMinus(new Node\Scalar\LNumber(42)));
259
260         $visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
261         $visitor->method('leaveNode')->willReturn(array(new Node\Scalar\DNumber(42.0)));
262
263         $traverser = new NodeTraverser();
264         $traverser->addVisitor($visitor);
265         $traverser->traverse($stmts);
266     }
267 }