Skip to content

Commit 1bf073a

Browse files
committed
Avoid most MockBuilder uses in NodeVisitor testing
This removes all the warnings about at() usage ... even though it is still used. Apparently warnings don't get emitted if the at() usage is inside a data provider?
1 parent 1721ae1 commit 1bf073a

File tree

2 files changed

+182
-118
lines changed

2 files changed

+182
-118
lines changed

test/PhpParser/NodeTraverserTest.php

Lines changed: 134 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ public function testNonModifying() {
1313
$echoNode = new Node\Stmt\Echo_([$str1Node, $str2Node]);
1414
$stmts = [$echoNode];
1515

16-
$visitor = $this->getMockBuilder(NodeVisitor::class)->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-
16+
$visitor = new NodeVisitorForTesting();
2717
$traverser = new NodeTraverser;
2818
$traverser->addVisitor($visitor);
2919

3020
$this->assertEquals($stmts, $traverser->traverse($stmts));
21+
$this->assertEquals([
22+
['beforeTraverse', $stmts],
23+
['enterNode', $echoNode],
24+
['enterNode', $str1Node],
25+
['leaveNode', $str1Node],
26+
['enterNode', $str2Node],
27+
['leaveNode', $str2Node],
28+
['leaveNode', $echoNode],
29+
['afterTraverse', $stmts],
30+
], $visitor->trace);
3131
}
3232

3333
public function testModifying() {
@@ -36,56 +36,39 @@ public function testModifying() {
3636
$printNode = new Expr\Print_($str1Node);
3737

3838
// first visitor changes the node, second verifies the change
39-
$visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock();
40-
$visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock();
41-
42-
// replace empty statements with string1 node
43-
$visitor1->expects($this->at(0))->method('beforeTraverse')->with([])
44-
->willReturn([$str1Node]);
45-
$visitor2->expects($this->at(0))->method('beforeTraverse')->with([$str1Node]);
46-
47-
// replace string1 node with print node
48-
$visitor1->expects($this->at(1))->method('enterNode')->with($str1Node)
49-
->willReturn($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-
->willReturn($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-
->willReturn($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-
->willReturn($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([$str1Node])
69-
->willReturn([]);
70-
$visitor2->expects($this->at(5))->method('afterTraverse')->with([]);
39+
$visitor1 = new NodeVisitorForTesting([
40+
['beforeTraverse', [], [$str1Node]],
41+
['enterNode', $str1Node, $printNode],
42+
['enterNode', $str1Node, $str2Node],
43+
['leaveNode', $str2Node, $str1Node],
44+
['leaveNode', $printNode, $str1Node],
45+
['afterTraverse', [$str1Node], []],
46+
]);
47+
$visitor2 = new NodeVisitorForTesting();
7148

7249
$traverser = new NodeTraverser;
7350
$traverser->addVisitor($visitor1);
7451
$traverser->addVisitor($visitor2);
7552

7653
// as all operations are reversed we end where we start
7754
$this->assertEquals([], $traverser->traverse([]));
55+
$this->assertEquals([
56+
['beforeTraverse', [$str1Node]],
57+
['enterNode', $printNode],
58+
['enterNode', $str2Node],
59+
['leaveNode', $str1Node],
60+
['leaveNode', $str1Node],
61+
['afterTraverse', []],
62+
], $visitor2->trace);
7863
}
7964

8065
public function testRemove() {
8166
$str1Node = new String_('Foo');
8267
$str2Node = new String_('Bar');
8368

84-
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
85-
86-
// remove the string1 node, leave the string2 node
87-
$visitor->expects($this->at(2))->method('leaveNode')->with($str1Node)
88-
->willReturn(NodeTraverser::REMOVE_NODE);
69+
$visitor = new NodeVisitorForTesting([
70+
['leaveNode', $str1Node, NodeTraverser::REMOVE_NODE],
71+
]);
8972

9073
$traverser = new NodeTraverser;
9174
$traverser->addVisitor($visitor);
@@ -100,11 +83,9 @@ public function testMerge() {
10083
$strR1 = new String_('Replacement 1');
10184
$strR2 = new String_('Replacement 2');
10285

103-
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
104-
105-
// replace strMiddle with strR1 and strR2 by merge
106-
$visitor->expects($this->at(4))->method('leaveNode')->with($strMiddle)
107-
->willReturn([$strR1, $strR2]);
86+
$visitor = new NodeVisitorForTesting([
87+
['leaveNode', $strMiddle, [$strR1, $strR2]],
88+
]);
10889

10990
$traverser = new NodeTraverser;
11091
$traverser->addVisitor($visitor);
@@ -133,34 +114,31 @@ public function testDontTraverseChildren() {
133114
$negNode = new Expr\UnaryMinus($mulNode);
134115
$stmts = [$printNode, $negNode];
135116

136-
$visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock();
137-
$visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock();
138-
139-
$visitor1->expects($this->at(1))->method('enterNode')->with($printNode)
140-
->willReturn(NodeTraverser::DONT_TRAVERSE_CHILDREN);
141-
$visitor2->expects($this->at(1))->method('enterNode')->with($printNode);
142-
143-
$visitor1->expects($this->at(2))->method('leaveNode')->with($printNode);
144-
$visitor2->expects($this->at(2))->method('leaveNode')->with($printNode);
145-
146-
$visitor1->expects($this->at(3))->method('enterNode')->with($negNode);
147-
$visitor2->expects($this->at(3))->method('enterNode')->with($negNode);
148-
149-
$visitor1->expects($this->at(4))->method('enterNode')->with($mulNode);
150-
$visitor2->expects($this->at(4))->method('enterNode')->with($mulNode)
151-
->willReturn(NodeTraverser::DONT_TRAVERSE_CHILDREN);
152-
153-
$visitor1->expects($this->at(5))->method('leaveNode')->with($mulNode);
154-
$visitor2->expects($this->at(5))->method('leaveNode')->with($mulNode);
155-
156-
$visitor1->expects($this->at(6))->method('leaveNode')->with($negNode);
157-
$visitor2->expects($this->at(6))->method('leaveNode')->with($negNode);
117+
$visitor1 = new NodeVisitorForTesting([
118+
['enterNode', $printNode, NodeTraverser::DONT_TRAVERSE_CHILDREN],
119+
]);
120+
$visitor2 = new NodeVisitorForTesting([
121+
['enterNode', $mulNode, NodeTraverser::DONT_TRAVERSE_CHILDREN],
122+
]);
123+
124+
$expectedTrace = [
125+
['beforeTraverse', $stmts],
126+
['enterNode', $printNode],
127+
['leaveNode', $printNode],
128+
['enterNode', $negNode],
129+
['enterNode', $mulNode],
130+
['leaveNode', $mulNode],
131+
['leaveNode', $negNode],
132+
['afterTraverse', $stmts],
133+
];
158134

159135
$traverser = new NodeTraverser;
160136
$traverser->addVisitor($visitor1);
161137
$traverser->addVisitor($visitor2);
162138

163139
$this->assertEquals($stmts, $traverser->traverse($stmts));
140+
$this->assertEquals($expectedTrace, $visitor1->trace);
141+
$this->assertEquals($expectedTrace, $visitor2->trace);
164142
}
165143

166144
public function testDontTraverseCurrentAndChildren() {
@@ -173,30 +151,36 @@ public function testDontTraverseCurrentAndChildren() {
173151
$negNode = new Expr\UnaryMinus($mulNode);
174152
$stmts = [$printNode, $negNode];
175153

176-
$visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock();
177-
$visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock();
178-
179-
$visitor1->expects($this->at(1))->method('enterNode')->with($printNode)
180-
->willReturn(NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN);
181-
$visitor1->expects($this->at(2))->method('leaveNode')->with($printNode);
182-
183-
$visitor1->expects($this->at(3))->method('enterNode')->with($negNode);
184-
$visitor2->expects($this->at(1))->method('enterNode')->with($negNode);
185-
186-
$visitor1->expects($this->at(4))->method('enterNode')->with($mulNode)
187-
->willReturn(NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN);
188-
$visitor1->expects($this->at(5))->method('leaveNode')->with($mulNode)->willReturn($divNode);
189-
190-
$visitor1->expects($this->at(6))->method('leaveNode')->with($negNode);
191-
$visitor2->expects($this->at(2))->method('leaveNode')->with($negNode);
154+
$visitor1 = new NodeVisitorForTesting([
155+
['enterNode', $printNode, NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN],
156+
['enterNode', $mulNode, NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN],
157+
['leaveNode', $mulNode, $divNode],
158+
]);
159+
$visitor2 = new NodeVisitorForTesting();
192160

193161
$traverser = new NodeTraverser;
194162
$traverser->addVisitor($visitor1);
195163
$traverser->addVisitor($visitor2);
196164

197165
$resultStmts = $traverser->traverse($stmts);
198-
199166
$this->assertInstanceOf(Expr\BinaryOp\Div::class, $resultStmts[1]->expr);
167+
168+
$this->assertEquals([
169+
['beforeTraverse', $stmts],
170+
['enterNode', $printNode],
171+
['leaveNode', $printNode],
172+
['enterNode', $negNode],
173+
['enterNode', $mulNode],
174+
['leaveNode', $mulNode],
175+
['leaveNode', $negNode],
176+
['afterTraverse', $resultStmts],
177+
], $visitor1->trace);
178+
$this->assertEquals([
179+
['beforeTraverse', $stmts],
180+
['enterNode', $negNode],
181+
['leaveNode', $negNode],
182+
['afterTraverse', $resultStmts],
183+
], $visitor2->trace);
200184
}
201185

202186
public function testStopTraversal() {
@@ -208,58 +192,90 @@ public function testStopTraversal() {
208192
$stmts = [$mulNode, $printNode];
209193

210194
// From enterNode() with array parent
211-
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
212-
$visitor->expects($this->at(1))->method('enterNode')->with($mulNode)
213-
->willReturn(NodeTraverser::STOP_TRAVERSAL);
214-
$visitor->expects($this->at(2))->method('afterTraverse');
195+
$visitor = new NodeVisitorForTesting([
196+
['enterNode', $mulNode, NodeTraverser::STOP_TRAVERSAL],
197+
]);
215198
$traverser = new NodeTraverser;
216199
$traverser->addVisitor($visitor);
217200
$this->assertEquals($stmts, $traverser->traverse($stmts));
201+
$this->assertEquals([
202+
['beforeTraverse', $stmts],
203+
['enterNode', $mulNode],
204+
['afterTraverse', $stmts],
205+
], $visitor->trace);
218206

219207
// From enterNode with Node parent
220-
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
221-
$visitor->expects($this->at(2))->method('enterNode')->with($varNode1)
222-
->willReturn(NodeTraverser::STOP_TRAVERSAL);
223-
$visitor->expects($this->at(3))->method('afterTraverse');
208+
$visitor = new NodeVisitorForTesting([
209+
['enterNode', $varNode1, NodeTraverser::STOP_TRAVERSAL],
210+
]);
224211
$traverser = new NodeTraverser;
225212
$traverser->addVisitor($visitor);
226213
$this->assertEquals($stmts, $traverser->traverse($stmts));
214+
$this->assertEquals([
215+
['beforeTraverse', $stmts],
216+
['enterNode', $mulNode],
217+
['enterNode', $varNode1],
218+
['afterTraverse', $stmts],
219+
], $visitor->trace);
227220

228221
// From leaveNode with Node parent
229-
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
230-
$visitor->expects($this->at(3))->method('leaveNode')->with($varNode1)
231-
->willReturn(NodeTraverser::STOP_TRAVERSAL);
232-
$visitor->expects($this->at(4))->method('afterTraverse');
222+
$visitor = new NodeVisitorForTesting([
223+
['leaveNode', $varNode1, NodeTraverser::STOP_TRAVERSAL],
224+
]);
233225
$traverser = new NodeTraverser;
234226
$traverser->addVisitor($visitor);
235227
$this->assertEquals($stmts, $traverser->traverse($stmts));
228+
$this->assertEquals([
229+
['beforeTraverse', $stmts],
230+
['enterNode', $mulNode],
231+
['enterNode', $varNode1],
232+
['leaveNode', $varNode1],
233+
['afterTraverse', $stmts],
234+
], $visitor->trace);
236235

237236
// From leaveNode with array parent
238-
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
239-
$visitor->expects($this->at(6))->method('leaveNode')->with($mulNode)
240-
->willReturn(NodeTraverser::STOP_TRAVERSAL);
241-
$visitor->expects($this->at(7))->method('afterTraverse');
237+
$visitor = new NodeVisitorForTesting([
238+
['leaveNode', $mulNode, NodeTraverser::STOP_TRAVERSAL],
239+
]);
242240
$traverser = new NodeTraverser;
243241
$traverser->addVisitor($visitor);
244242
$this->assertEquals($stmts, $traverser->traverse($stmts));
243+
$this->assertEquals([
244+
['beforeTraverse', $stmts],
245+
['enterNode', $mulNode],
246+
['enterNode', $varNode1],
247+
['leaveNode', $varNode1],
248+
['enterNode', $varNode2],
249+
['leaveNode', $varNode2],
250+
['leaveNode', $mulNode],
251+
['afterTraverse', $stmts],
252+
], $visitor->trace);
245253

246254
// Check that pending array modifications are still carried out
247-
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
248-
$visitor->expects($this->at(6))->method('leaveNode')->with($mulNode)
249-
->willReturn(NodeTraverser::REMOVE_NODE);
250-
$visitor->expects($this->at(7))->method('enterNode')->with($printNode)
251-
->willReturn(NodeTraverser::STOP_TRAVERSAL);
252-
$visitor->expects($this->at(8))->method('afterTraverse');
255+
$visitor = new NodeVisitorForTesting([
256+
['leaveNode', $mulNode, NodeTraverser::REMOVE_NODE],
257+
['enterNode', $printNode, NodeTraverser::STOP_TRAVERSAL],
258+
]);
253259
$traverser = new NodeTraverser;
254260
$traverser->addVisitor($visitor);
255261
$this->assertEquals([$printNode], $traverser->traverse($stmts));
256-
262+
$this->assertEquals([
263+
['beforeTraverse', $stmts],
264+
['enterNode', $mulNode],
265+
['enterNode', $varNode1],
266+
['leaveNode', $varNode1],
267+
['enterNode', $varNode2],
268+
['leaveNode', $varNode2],
269+
['leaveNode', $mulNode],
270+
['enterNode', $printNode],
271+
['afterTraverse', [$printNode]],
272+
], $visitor->trace);
257273
}
258274

259275
public function testRemovingVisitor() {
260-
$visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock();
261-
$visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock();
262-
$visitor3 = $this->getMockBuilder(NodeVisitor::class)->getMock();
276+
$visitor1 = new class extends NodeVisitorAbstract {};
277+
$visitor2 = new class extends NodeVisitorAbstract {};
278+
$visitor3 = new class extends NodeVisitorAbstract {};
263279

264280
$traverser = new NodeTraverser;
265281
$traverser->addVisitor($visitor1);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace PhpParser;
4+
5+
class NodeVisitorForTesting implements NodeVisitor {
6+
public $trace = [];
7+
private $returns;
8+
private $returnsPos;
9+
10+
public function __construct(array $returns = []) {
11+
$this->returns = $returns;
12+
$this->returnsPos = 0;
13+
}
14+
15+
public function beforeTraverse(array $nodes) {
16+
return $this->traceEvent('beforeTraverse', $nodes);
17+
}
18+
19+
public function enterNode(Node $node) {
20+
return $this->traceEvent('enterNode', $node);
21+
}
22+
23+
public function leaveNode(Node $node) {
24+
return $this->traceEvent('leaveNode', $node);
25+
}
26+
27+
public function afterTraverse(array $nodes) {
28+
return $this->traceEvent('afterTraverse', $nodes);
29+
}
30+
31+
private function traceEvent(string $method, $param) {
32+
$this->trace[] = [$method, $param];
33+
if ($this->returnsPos < count($this->returns)) {
34+
$currentReturn = $this->returns[$this->returnsPos];
35+
if ($currentReturn[0] === $method && $currentReturn[1] === $param) {
36+
$this->returnsPos++;
37+
return $currentReturn[2];
38+
}
39+
}
40+
return null;
41+
}
42+
43+
public function __destruct() {
44+
if ($this->returnsPos !== count($this->returns)) {
45+
throw new \Exception("Expected event did not occur");
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)