OLD | NEW |
| (Empty) |
1 // Copyright 2012 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 // Flags: --expose-debug-as debug | |
29 | |
30 // Get the Debug object exposed from the debug context global object. | |
31 var Debug = debug.Debug; | |
32 var DebugCommandProcessor = debug.DebugCommandProcessor; | |
33 | |
34 // Accepts a function/closure 'fun' that must have a debugger statement inside. | |
35 // A variable 'variable_name' must be initialized before debugger statement | |
36 // and returned after the statement. The test will alter variable value when | |
37 // on debugger statement and check that returned value reflects the change. | |
38 function RunPauseTest(scope_number, expected_old_result, variable_name, | |
39 new_value, expected_new_result, fun) { | |
40 var actual_old_result = fun(); | |
41 assertEquals(expected_old_result, actual_old_result); | |
42 | |
43 var listener_delegate; | |
44 var listener_called = false; | |
45 var exception = null; | |
46 | |
47 function listener_delegate(exec_state) { | |
48 var scope = exec_state.frame(0).scope(scope_number); | |
49 scope.setVariableValue(variable_name, new_value); | |
50 } | |
51 | |
52 function listener(event, exec_state, event_data, data) { | |
53 try { | |
54 if (event == Debug.DebugEvent.Break) { | |
55 listener_called = true; | |
56 listener_delegate(exec_state); | |
57 } | |
58 } catch (e) { | |
59 exception = e; | |
60 } | |
61 } | |
62 | |
63 // Add the debug event listener. | |
64 Debug.setListener(listener); | |
65 | |
66 var actual_new_result; | |
67 try { | |
68 actual_new_result = fun(); | |
69 } finally { | |
70 Debug.setListener(null); | |
71 } | |
72 | |
73 if (exception != null) { | |
74 assertUnreachable("Exception in listener\n" + exception.stack); | |
75 } | |
76 assertTrue(listener_called); | |
77 | |
78 assertEquals(expected_new_result, actual_new_result); | |
79 } | |
80 | |
81 // Accepts a closure 'fun' that returns a variable from its outer scope. | |
82 // The test changes the value of variable via the handle to function and checks | |
83 // that the return value changed accordingly. | |
84 function RunClosureTest(scope_number, expected_old_result, variable_name, | |
85 new_value, expected_new_result, fun) { | |
86 var actual_old_result = fun(); | |
87 assertEquals(expected_old_result, actual_old_result); | |
88 | |
89 var fun_mirror = Debug.MakeMirror(fun); | |
90 | |
91 var scope = fun_mirror.scope(scope_number); | |
92 scope.setVariableValue(variable_name, new_value); | |
93 | |
94 var actual_new_result = fun(); | |
95 | |
96 assertEquals(expected_new_result, actual_new_result); | |
97 } | |
98 | |
99 | |
100 function ClosureTestCase(scope_index, old_result, variable_name, new_value, | |
101 new_result, success_expected, factory) { | |
102 this.scope_index_ = scope_index; | |
103 this.old_result_ = old_result; | |
104 this.variable_name_ = variable_name; | |
105 this.new_value_ = new_value; | |
106 this.new_result_ = new_result; | |
107 this.success_expected_ = success_expected; | |
108 this.factory_ = factory; | |
109 } | |
110 | |
111 ClosureTestCase.prototype.run_pause_test = function() { | |
112 var th = this; | |
113 var fun = this.factory_(true); | |
114 this.run_and_catch_(function() { | |
115 RunPauseTest(th.scope_index_ + 1, th.old_result_, th.variable_name_, | |
116 th.new_value_, th.new_result_, fun); | |
117 }); | |
118 } | |
119 | |
120 ClosureTestCase.prototype.run_closure_test = function() { | |
121 var th = this; | |
122 var fun = this.factory_(false); | |
123 this.run_and_catch_(function() { | |
124 RunClosureTest(th.scope_index_, th.old_result_, th.variable_name_, | |
125 th.new_value_, th.new_result_, fun); | |
126 }); | |
127 } | |
128 | |
129 ClosureTestCase.prototype.run_and_catch_ = function(runnable) { | |
130 if (this.success_expected_) { | |
131 runnable(); | |
132 } else { | |
133 assertThrows(runnable); | |
134 } | |
135 } | |
136 | |
137 | |
138 // Test scopes visible from closures. | |
139 | |
140 var closure_test_cases = [ | |
141 new ClosureTestCase(0, 'cat', 'v1', 5, 5, true, | |
142 function Factory(debug_stop) { | |
143 var v1 = 'cat'; | |
144 return function() { | |
145 if (debug_stop) debugger; | |
146 return v1; | |
147 } | |
148 }), | |
149 | |
150 new ClosureTestCase(0, 4, 't', 7, 9, true, function Factory(debug_stop) { | |
151 var t = 2; | |
152 var r = eval("t"); | |
153 return function() { | |
154 if (debug_stop) debugger; | |
155 return r + t; | |
156 } | |
157 }), | |
158 | |
159 new ClosureTestCase(0, 6, 't', 10, 13, true, function Factory(debug_stop) { | |
160 var t = 2; | |
161 var r = eval("t = 3"); | |
162 return function() { | |
163 if (debug_stop) debugger; | |
164 return r + t; | |
165 } | |
166 }), | |
167 | |
168 new ClosureTestCase(0, 17, 's', 'Bird', 'Bird', true, | |
169 function Factory(debug_stop) { | |
170 eval("var s = 17"); | |
171 return function() { | |
172 if (debug_stop) debugger; | |
173 return s; | |
174 } | |
175 }), | |
176 | |
177 new ClosureTestCase(2, 'capybara', 'foo', 77, 77, true, | |
178 function Factory(debug_stop) { | |
179 var foo = "capybara"; | |
180 return (function() { | |
181 var bar = "fish"; | |
182 try { | |
183 throw {name: "test exception"}; | |
184 } catch (e) { | |
185 return function() { | |
186 if (debug_stop) debugger; | |
187 bar = "beast"; | |
188 return foo; | |
189 } | |
190 } | |
191 })(); | |
192 }), | |
193 | |
194 new ClosureTestCase(0, 'AlphaBeta', 'eee', 5, '5Beta', true, | |
195 function Factory(debug_stop) { | |
196 var foo = "Beta"; | |
197 return (function() { | |
198 var bar = "fish"; | |
199 try { | |
200 throw "Alpha"; | |
201 } catch (eee) { | |
202 return function() { | |
203 if (debug_stop) debugger; | |
204 return eee + foo; | |
205 } | |
206 } | |
207 })(); | |
208 }) | |
209 ]; | |
210 | |
211 for (var i = 0; i < closure_test_cases.length; i++) { | |
212 closure_test_cases[i].run_pause_test(); | |
213 } | |
214 | |
215 for (var i = 0; i < closure_test_cases.length; i++) { | |
216 closure_test_cases[i].run_closure_test(); | |
217 } | |
218 | |
219 | |
220 // Test local scope. | |
221 | |
222 RunPauseTest(0, 'HelloYou', 'u', 'We', 'HelloWe', (function Factory() { | |
223 return function() { | |
224 var u = "You"; | |
225 var v = "Hello"; | |
226 debugger; | |
227 return v + u; | |
228 } | |
229 })()); | |
230 | |
231 RunPauseTest(0, 'Helloworld', 'p', 'GoodBye', 'HelloGoodBye', | |
232 (function Factory() { | |
233 function H(p) { | |
234 var v = "Hello"; | |
235 debugger; | |
236 return v + p; | |
237 } | |
238 return function() { | |
239 return H("world"); | |
240 } | |
241 })()); | |
242 | |
243 RunPauseTest(0, 'mouse', 'v1', 'dog', 'dog', (function Factory() { | |
244 return function() { | |
245 var v1 = 'cat'; | |
246 eval("v1 = 'mouse'"); | |
247 debugger; | |
248 return v1; | |
249 } | |
250 })()); | |
251 | |
252 RunPauseTest(0, 'mouse', 'v1', 'dog', 'dog', (function Factory() { | |
253 return function() { | |
254 eval("var v1 = 'mouse'"); | |
255 debugger; | |
256 return v1; | |
257 } | |
258 })()); | |
259 | |
260 | |
261 // Check that we correctly update local variable that | |
262 // is referenced from an inner closure. | |
263 RunPauseTest(0, 'Blue', 'v', 'Green', 'Green', (function Factory() { | |
264 return function() { | |
265 function A() { | |
266 var v = "Blue"; | |
267 function Inner() { | |
268 return void v; | |
269 } | |
270 debugger; | |
271 return v; | |
272 } | |
273 return A(); | |
274 } | |
275 })()); | |
276 | |
277 // Check that we correctly update parameter, that is known to be stored | |
278 // both on stack and in heap. | |
279 RunPauseTest(0, 5, 'p', 2012, 2012, (function Factory() { | |
280 return function() { | |
281 function A(p) { | |
282 function Inner() { | |
283 return void p; | |
284 } | |
285 debugger; | |
286 return p; | |
287 } | |
288 return A(5); | |
289 } | |
290 })()); | |
291 | |
292 | |
293 // Test value description protocol JSON | |
294 | |
295 assertEquals(true, DebugCommandProcessor.resolveValue_({value: true})); | |
296 | |
297 assertSame(null, DebugCommandProcessor.resolveValue_({type: "null"})); | |
298 assertSame(undefined, | |
299 DebugCommandProcessor.resolveValue_({type: "undefined"})); | |
300 | |
301 assertSame("123", DebugCommandProcessor.resolveValue_( | |
302 {type: "string", stringDescription: "123"})); | |
303 assertSame(123, DebugCommandProcessor.resolveValue_( | |
304 {type: "number", stringDescription: "123"})); | |
305 | |
306 assertSame(Number, DebugCommandProcessor.resolveValue_( | |
307 {handle: Debug.MakeMirror(Number).handle()})); | |
308 assertSame(RunClosureTest, DebugCommandProcessor.resolveValue_( | |
309 {handle: Debug.MakeMirror(RunClosureTest).handle()})); | |
310 | |
311 | |
312 // Test script-scope variable. | |
313 let abc = 12; | |
314 { | |
315 let exception; | |
316 function listener(event, exec_state) { | |
317 try { | |
318 if (event == Debug.DebugEvent.Break) { | |
319 let scope_count = exec_state.frame().scopeCount(); | |
320 let script_scope = exec_state.frame().scope(scope_count - 2); | |
321 assertTrue(script_scope.isScope()); | |
322 assertEquals(debug.ScopeType.Script, script_scope.scopeType()); | |
323 script_scope.setVariableValue('abc', 42); | |
324 } | |
325 } catch(e) { exception = e } | |
326 } | |
327 | |
328 Debug.setListener(listener); | |
329 assertEquals(12, abc); | |
330 debugger; | |
331 assertEquals(42, abc); | |
332 | |
333 if (exception != null) { | |
334 assertUnreachable("Exception in listener\n" + exception.stack); | |
335 } | |
336 } | |
337 | |
338 Debug.setListener(null); | |
OLD | NEW |