OLD | NEW |
| (Empty) |
1 // Copyright 2011 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 --harmony-scoping | |
29 // The functions used for testing backtraces. They are at the top to make the | |
30 // testing of source line/column easier. | |
31 | |
32 "use strict"; | |
33 | |
34 // Get the Debug object exposed from the debug context global object. | |
35 var Debug = debug.Debug; | |
36 | |
37 var test_name; | |
38 var listener_delegate; | |
39 var listener_called; | |
40 var exception; | |
41 var begin_test_count = 0; | |
42 var end_test_count = 0; | |
43 var break_count = 0; | |
44 | |
45 | |
46 // Debug event listener which delegates. | |
47 function listener(event, exec_state, event_data, data) { | |
48 try { | |
49 if (event == Debug.DebugEvent.Break) { | |
50 break_count++; | |
51 listener_called = true; | |
52 listener_delegate(exec_state); | |
53 } | |
54 } catch (e) { | |
55 exception = e; | |
56 } | |
57 } | |
58 | |
59 // Add the debug event listener. | |
60 Debug.setListener(listener); | |
61 | |
62 | |
63 // Initialize for a new test. | |
64 function BeginTest(name) { | |
65 test_name = name; | |
66 listener_delegate = null; | |
67 listener_called = false; | |
68 exception = null; | |
69 begin_test_count++; | |
70 } | |
71 | |
72 | |
73 // Check result of a test. | |
74 function EndTest() { | |
75 assertTrue(listener_called, "listerner not called for " + test_name); | |
76 assertNull(exception, test_name, exception); | |
77 end_test_count++; | |
78 } | |
79 | |
80 var global_object = this; | |
81 | |
82 // Check that the scope chain contains the expected types of scopes. | |
83 function CheckScopeChain(scopes, exec_state) { | |
84 assertEquals(scopes.length, exec_state.frame().scopeCount()); | |
85 for (var i = 0; i < scopes.length; i++) { | |
86 var scope = exec_state.frame().scope(i); | |
87 assertTrue(scope.isScope()); | |
88 assertEquals(scopes[i], scope.scopeType()); | |
89 | |
90 // Check the global object when hitting the global scope. | |
91 if (scopes[i] == debug.ScopeType.Global) { | |
92 // Objects don't have same class (one is "global", other is "Object", | |
93 // so just check the properties directly. | |
94 assertPropertiesEqual(global_object, scope.scopeObject().value()); | |
95 } | |
96 } | |
97 | |
98 // Get the debug command processor. | |
99 var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); | |
100 | |
101 // Send a scopes request and check the result. | |
102 var json; | |
103 var request_json = '{"seq":0,"type":"request","command":"scopes"}'; | |
104 var response_json = dcp.processDebugJSONRequest(request_json); | |
105 var response = JSON.parse(response_json); | |
106 assertEquals(scopes.length, response.body.scopes.length); | |
107 for (var i = 0; i < scopes.length; i++) { | |
108 assertEquals(i, response.body.scopes[i].index); | |
109 assertEquals(scopes[i], response.body.scopes[i].type); | |
110 if (scopes[i] == debug.ScopeType.Local || | |
111 scopes[i] == debug.ScopeType.Script || | |
112 scopes[i] == debug.ScopeType.Closure) { | |
113 assertTrue(response.body.scopes[i].object.ref < 0); | |
114 } else { | |
115 assertTrue(response.body.scopes[i].object.ref >= 0); | |
116 } | |
117 var found = false; | |
118 for (var j = 0; j < response.refs.length && !found; j++) { | |
119 found = response.refs[j].handle == response.body.scopes[i].object.ref; | |
120 } | |
121 assertTrue(found, "Scope object " + response.body.scopes[i].object.ref + " n
ot found"); | |
122 } | |
123 } | |
124 | |
125 // Check that the content of the scope is as expected. For functions just check | |
126 // that there is a function. | |
127 function CheckScopeContent(content, number, exec_state) { | |
128 var scope = exec_state.frame().scope(number); | |
129 var count = 0; | |
130 for (var p in content) { | |
131 var property_mirror = scope.scopeObject().property(p); | |
132 if (property_mirror.isUndefined()) { | |
133 print('property ' + p + ' not found in scope'); | |
134 } | |
135 assertFalse(property_mirror.isUndefined(), 'property ' + p + ' not found in
scope'); | |
136 if (typeof(content[p]) === 'function') { | |
137 assertTrue(property_mirror.value().isFunction()); | |
138 } else { | |
139 assertEquals(content[p], property_mirror.value().value(), 'property ' + p
+ ' has unexpected value'); | |
140 } | |
141 count++; | |
142 } | |
143 | |
144 // 'arguments' and might be exposed in the local and closure scope. Just | |
145 // ignore this. | |
146 var scope_size = scope.scopeObject().properties().length; | |
147 if (!scope.scopeObject().property('arguments').isUndefined()) { | |
148 scope_size--; | |
149 } | |
150 // Skip property with empty name. | |
151 if (!scope.scopeObject().property('').isUndefined()) { | |
152 scope_size--; | |
153 } | |
154 | |
155 if (count != scope_size) { | |
156 print('Names found in scope:'); | |
157 var names = scope.scopeObject().propertyNames(); | |
158 for (var i = 0; i < names.length; i++) { | |
159 print(names[i]); | |
160 } | |
161 } | |
162 assertEquals(count, scope_size); | |
163 | |
164 // Get the debug command processor. | |
165 var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); | |
166 | |
167 // Send a scope request for information on a single scope and check the | |
168 // result. | |
169 var request_json = '{"seq":0,"type":"request","command":"scope","arguments":{"
number":'; | |
170 request_json += scope.scopeIndex(); | |
171 request_json += '}}'; | |
172 var response_json = dcp.processDebugJSONRequest(request_json); | |
173 var response = JSON.parse(response_json); | |
174 assertEquals(scope.scopeType(), response.body.type); | |
175 assertEquals(number, response.body.index); | |
176 if (scope.scopeType() == debug.ScopeType.Local || | |
177 scope.scopeType() == debug.ScopeType.Closure) { | |
178 assertTrue(response.body.object.ref < 0); | |
179 } else { | |
180 assertTrue(response.body.object.ref >= 0); | |
181 } | |
182 var found = false; | |
183 for (var i = 0; i < response.refs.length && !found; i++) { | |
184 found = response.refs[i].handle == response.body.object.ref; | |
185 } | |
186 assertTrue(found, "Scope object " + response.body.object.ref + " not found"); | |
187 } | |
188 | |
189 | |
190 // Simple empty block scope in local scope. | |
191 BeginTest("Local block 1"); | |
192 | |
193 function local_block_1() { | |
194 { | |
195 debugger; | |
196 } | |
197 } | |
198 | |
199 listener_delegate = function(exec_state) { | |
200 CheckScopeChain([debug.ScopeType.Local, | |
201 debug.ScopeType.Script, | |
202 debug.ScopeType.Global], exec_state); | |
203 CheckScopeContent({}, 0, exec_state); | |
204 }; | |
205 local_block_1(); | |
206 EndTest(); | |
207 | |
208 | |
209 // Simple empty block scope in local scope with a parameter. | |
210 BeginTest("Local 2"); | |
211 | |
212 function local_2(a) { | |
213 { | |
214 debugger; | |
215 } | |
216 } | |
217 | |
218 listener_delegate = function(exec_state) { | |
219 CheckScopeChain([debug.ScopeType.Local, | |
220 debug.ScopeType.Script, | |
221 debug.ScopeType.Global], exec_state); | |
222 CheckScopeContent({a:1}, 0, exec_state); | |
223 }; | |
224 local_2(1); | |
225 EndTest(); | |
226 | |
227 | |
228 // Local scope with a parameter and a local variable. | |
229 BeginTest("Local 3"); | |
230 | |
231 function local_3(a) { | |
232 let x = 3; | |
233 debugger; | |
234 } | |
235 | |
236 listener_delegate = function(exec_state) { | |
237 CheckScopeChain([debug.ScopeType.Local, | |
238 debug.ScopeType.Script, | |
239 debug.ScopeType.Global], exec_state); | |
240 CheckScopeContent({a:1,x:3}, 0, exec_state); | |
241 }; | |
242 local_3(1); | |
243 EndTest(); | |
244 | |
245 | |
246 // Local scope with parameters and local variables. | |
247 BeginTest("Local 4"); | |
248 | |
249 function local_4(a, b) { | |
250 let x = 3; | |
251 let y = 4; | |
252 debugger; | |
253 } | |
254 | |
255 listener_delegate = function(exec_state) { | |
256 CheckScopeChain([debug.ScopeType.Local, | |
257 debug.ScopeType.Script, | |
258 debug.ScopeType.Global], exec_state); | |
259 CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state); | |
260 }; | |
261 local_4(1, 2); | |
262 EndTest(); | |
263 | |
264 | |
265 // Single variable in a block scope. | |
266 BeginTest("Local 5"); | |
267 | |
268 function local_5(a) { | |
269 { | |
270 let x = 5; | |
271 debugger; | |
272 } | |
273 } | |
274 | |
275 listener_delegate = function(exec_state) { | |
276 CheckScopeChain([debug.ScopeType.Block, | |
277 debug.ScopeType.Local, | |
278 debug.ScopeType.Script, | |
279 debug.ScopeType.Global], exec_state); | |
280 CheckScopeContent({x:5}, 0, exec_state); | |
281 CheckScopeContent({a:1}, 1, exec_state); | |
282 }; | |
283 local_5(1); | |
284 EndTest(); | |
285 | |
286 | |
287 // Two variables in a block scope. | |
288 BeginTest("Local 6"); | |
289 | |
290 function local_6(a) { | |
291 { | |
292 let x = 6; | |
293 let y = 7; | |
294 debugger; | |
295 } | |
296 } | |
297 | |
298 listener_delegate = function(exec_state) { | |
299 CheckScopeChain([debug.ScopeType.Block, | |
300 debug.ScopeType.Local, | |
301 debug.ScopeType.Script, | |
302 debug.ScopeType.Global], exec_state); | |
303 CheckScopeContent({x:6,y:7}, 0, exec_state); | |
304 CheckScopeContent({a:1}, 1, exec_state); | |
305 }; | |
306 local_6(1); | |
307 EndTest(); | |
308 | |
309 | |
310 // Two variables in a block scope. | |
311 BeginTest("Local 7"); | |
312 | |
313 function local_7(a) { | |
314 { | |
315 { | |
316 let x = 8; | |
317 debugger; | |
318 } | |
319 } | |
320 } | |
321 | |
322 listener_delegate = function(exec_state) { | |
323 CheckScopeChain([debug.ScopeType.Block, | |
324 debug.ScopeType.Local, | |
325 debug.ScopeType.Script, | |
326 debug.ScopeType.Global], exec_state); | |
327 CheckScopeContent({x:8}, 0, exec_state); | |
328 CheckScopeContent({a:1}, 1, exec_state); | |
329 }; | |
330 local_7(1); | |
331 EndTest(); | |
332 | |
333 | |
334 // Simple closure formed by returning an inner function referering to an outer | |
335 // block local variable and an outer function's parameter. | |
336 BeginTest("Closure 1"); | |
337 | |
338 function closure_1(a) { | |
339 var x = 2; | |
340 let y = 3; | |
341 if (true) { | |
342 let z = 4; | |
343 function f() { | |
344 debugger; | |
345 return a + x + y + z; | |
346 }; | |
347 return f; | |
348 } | |
349 } | |
350 | |
351 listener_delegate = function(exec_state) { | |
352 CheckScopeChain([debug.ScopeType.Local, | |
353 debug.ScopeType.Block, | |
354 debug.ScopeType.Closure, | |
355 debug.ScopeType.Script, | |
356 debug.ScopeType.Global], exec_state); | |
357 CheckScopeContent({}, 0, exec_state); | |
358 CheckScopeContent({a:1,x:2,y:3}, 2, exec_state); | |
359 }; | |
360 closure_1(1)(); | |
361 EndTest(); | |
362 | |
363 | |
364 // Simple for-in loop over the keys of an object. | |
365 BeginTest("For loop 1"); | |
366 | |
367 function for_loop_1() { | |
368 for (let x in {y:undefined}) { | |
369 debugger; | |
370 } | |
371 } | |
372 | |
373 listener_delegate = function(exec_state) { | |
374 CheckScopeChain([debug.ScopeType.Block, | |
375 debug.ScopeType.Local, | |
376 debug.ScopeType.Script, | |
377 debug.ScopeType.Global], exec_state); | |
378 CheckScopeContent({x:'y'}, 0, exec_state); | |
379 // The function scope contains a temporary iteration variable, but it is | |
380 // hidden to the debugger. | |
381 CheckScopeContent({}, 1, exec_state); | |
382 }; | |
383 for_loop_1(); | |
384 EndTest(); | |
385 | |
386 | |
387 // For-in loop over the keys of an object with a block scoped let variable | |
388 // shadowing the iteration variable. | |
389 BeginTest("For loop 2"); | |
390 | |
391 function for_loop_2() { | |
392 for (let x in {y:undefined}) { | |
393 let x = 3; | |
394 debugger; | |
395 } | |
396 } | |
397 | |
398 listener_delegate = function(exec_state) { | |
399 CheckScopeChain([debug.ScopeType.Block, | |
400 debug.ScopeType.Block, | |
401 debug.ScopeType.Local, | |
402 debug.ScopeType.Script, | |
403 debug.ScopeType.Global], exec_state); | |
404 CheckScopeContent({x:3}, 0, exec_state); | |
405 CheckScopeContent({x:'y'}, 1, exec_state); | |
406 // The function scope contains a temporary iteration variable, hidden to the | |
407 // debugger. | |
408 CheckScopeContent({}, 2, exec_state); | |
409 }; | |
410 for_loop_2(); | |
411 EndTest(); | |
412 | |
413 | |
414 // Simple for loop. | |
415 BeginTest("For loop 3"); | |
416 | |
417 function for_loop_3() { | |
418 for (let x = 3; x < 4; ++x) { | |
419 debugger; | |
420 } | |
421 } | |
422 | |
423 listener_delegate = function(exec_state) { | |
424 CheckScopeChain([debug.ScopeType.Block, | |
425 debug.ScopeType.Block, | |
426 debug.ScopeType.Local, | |
427 debug.ScopeType.Script, | |
428 debug.ScopeType.Global], exec_state); | |
429 CheckScopeContent({x:3}, 0, exec_state); | |
430 CheckScopeContent({x:3}, 1, exec_state); | |
431 CheckScopeContent({}, 2, exec_state); | |
432 }; | |
433 for_loop_3(); | |
434 EndTest(); | |
435 | |
436 | |
437 // For loop with a block scoped let variable shadowing the iteration variable. | |
438 BeginTest("For loop 4"); | |
439 | |
440 function for_loop_4() { | |
441 for (let x = 3; x < 4; ++x) { | |
442 let x = 5; | |
443 debugger; | |
444 } | |
445 } | |
446 | |
447 listener_delegate = function(exec_state) { | |
448 CheckScopeChain([debug.ScopeType.Block, | |
449 debug.ScopeType.Block, | |
450 debug.ScopeType.Block, | |
451 debug.ScopeType.Local, | |
452 debug.ScopeType.Script, | |
453 debug.ScopeType.Global], exec_state); | |
454 CheckScopeContent({x:5}, 0, exec_state); | |
455 CheckScopeContent({x:3}, 1, exec_state); | |
456 CheckScopeContent({x:3}, 2, exec_state); | |
457 CheckScopeContent({}, 3, exec_state); | |
458 }; | |
459 for_loop_4(); | |
460 EndTest(); | |
461 | |
462 | |
463 // For loop with two variable declarations. | |
464 BeginTest("For loop 5"); | |
465 | |
466 function for_loop_5() { | |
467 for (let x = 3, y = 5; x < 4; ++x) { | |
468 debugger; | |
469 } | |
470 } | |
471 | |
472 listener_delegate = function(exec_state) { | |
473 CheckScopeChain([debug.ScopeType.Block, | |
474 debug.ScopeType.Block, | |
475 debug.ScopeType.Local, | |
476 debug.ScopeType.Script, | |
477 debug.ScopeType.Global], exec_state); | |
478 CheckScopeContent({x:3,y:5}, 0, exec_state); | |
479 CheckScopeContent({x:3,y:5}, 1, exec_state); | |
480 CheckScopeContent({}, 2, exec_state); | |
481 }; | |
482 for_loop_5(); | |
483 EndTest(); | |
484 | |
485 | |
486 // Uninitialized variables | |
487 BeginTest("Uninitialized 1"); | |
488 | |
489 function uninitialized_1() { | |
490 { | |
491 debugger; | |
492 let x = 1; | |
493 } | |
494 } | |
495 | |
496 listener_delegate = function(exec_state) { | |
497 CheckScopeChain([debug.ScopeType.Block, | |
498 debug.ScopeType.Local, | |
499 debug.ScopeType.Script, | |
500 debug.ScopeType.Global], exec_state); | |
501 CheckScopeContent({}, 0, exec_state); | |
502 }; | |
503 uninitialized_1(); | |
504 EndTest(); | |
OLD | NEW |