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