Home | History | Annotate | Download | only in es6
      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 --allow-natives-syntax
     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     print(e, e.stack);
     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, exception);
     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.Script ||
    113         scopes[i] == debug.ScopeType.Closure) {
    114       assertTrue(response.body.scopes[i].object.ref < 0);
    115     } else {
    116       assertTrue(response.body.scopes[i].object.ref >= 0);
    117     }
    118     var found = false;
    119     for (var j = 0; j < response.refs.length && !found; j++) {
    120       found = response.refs[j].handle == response.body.scopes[i].object.ref;
    121     }
    122     assertTrue(found, "Scope object " + response.body.scopes[i].object.ref + " not found");
    123   }
    124 }
    125 
    126 // Check that the content of the scope is as expected. For functions just check
    127 // that there is a function.
    128 function CheckScopeContent(content, number, exec_state) {
    129   var scope = exec_state.frame().scope(number);
    130   var count = 0;
    131   for (var p in content) {
    132     var property_mirror = scope.scopeObject().property(p);
    133     if (property_mirror.isUndefined()) {
    134       print('property ' + p + ' not found in scope');
    135     }
    136     assertFalse(property_mirror.isUndefined(), 'property ' + p + ' not found in scope');
    137     if (typeof(content[p]) === 'function') {
    138       assertTrue(property_mirror.value().isFunction());
    139     } else {
    140       assertEquals(content[p], property_mirror.value().value(), 'property ' + p + ' has unexpected value');
    141     }
    142     count++;
    143   }
    144 
    145   // 'arguments' and might be exposed in the local and closure scope. Just
    146   // ignore this.
    147   var scope_size = scope.scopeObject().properties().length;
    148   if (!scope.scopeObject().property('arguments').isUndefined()) {
    149     scope_size--;
    150   }
    151   // Temporary variables introduced by the parser have not been materialized.
    152   assertTrue(scope.scopeObject().property('').isUndefined());
    153 
    154   if (count != scope_size) {
    155     print('Names found in scope:');
    156     var names = scope.scopeObject().propertyNames();
    157     for (var i = 0; i < names.length; i++) {
    158       print(names[i]);
    159     }
    160   }
    161   assertEquals(count, scope_size);
    162 
    163   // Get the debug command processor.
    164   var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
    165 
    166   // Send a scope request for information on a single scope and check the
    167   // result.
    168   var request_json = '{"seq":0,"type":"request","command":"scope","arguments":{"number":';
    169   request_json += scope.scopeIndex();
    170   request_json += '}}';
    171   var response_json = dcp.processDebugJSONRequest(request_json);
    172   var response = JSON.parse(response_json);
    173   assertEquals(scope.scopeType(), response.body.type);
    174   assertEquals(number, response.body.index);
    175   if (scope.scopeType() == debug.ScopeType.Local ||
    176       scope.scopeType() == debug.ScopeType.Closure) {
    177     assertTrue(response.body.object.ref < 0);
    178   } else {
    179     assertTrue(response.body.object.ref >= 0);
    180   }
    181   var found = false;
    182   for (var i = 0; i < response.refs.length && !found; i++) {
    183     found = response.refs[i].handle == response.body.object.ref;
    184   }
    185   assertTrue(found, "Scope object " + response.body.object.ref + " not found");
    186 }
    187 
    188 
    189 function assertEqualsUnlessOptimized(expected, value, f) {
    190   try {
    191     assertEquals(expected, value);
    192   } catch (e) {
    193     assertOptimized(f);
    194   }
    195 }
    196 
    197 // Simple empty block scope in local scope.
    198 BeginTest("Local block 1");
    199 
    200 function local_block_1() {
    201   {
    202     debugger;
    203   }
    204 }
    205 
    206 listener_delegate = function(exec_state) {
    207   CheckScopeChain([debug.ScopeType.Local,
    208                    debug.ScopeType.Script,
    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.Script,
    228                    debug.ScopeType.Global], exec_state);
    229   CheckScopeContent({a:1}, 0, exec_state);
    230 };
    231 local_2(1);
    232 EndTest();
    233 
    234 
    235 // Local scope with a parameter and a local variable.
    236 BeginTest("Local 3");
    237 
    238 function local_3(a) {
    239   let x = 3;
    240   debugger;
    241 }
    242 
    243 listener_delegate = function(exec_state) {
    244   CheckScopeChain([debug.ScopeType.Local,
    245                    debug.ScopeType.Script,
    246                    debug.ScopeType.Global], exec_state);
    247   CheckScopeContent({a:1,x:3}, 0, exec_state);
    248 };
    249 local_3(1);
    250 EndTest();
    251 
    252 
    253 // Local scope with parameters and local variables.
    254 BeginTest("Local 4");
    255 
    256 function local_4(a, b) {
    257   let x = 3;
    258   let y = 4;
    259   debugger;
    260 }
    261 
    262 listener_delegate = function(exec_state) {
    263   CheckScopeChain([debug.ScopeType.Local,
    264                    debug.ScopeType.Script,
    265                    debug.ScopeType.Global], exec_state);
    266   CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state);
    267 };
    268 local_4(1, 2);
    269 EndTest();
    270 
    271 
    272 // Single variable in a block scope.
    273 BeginTest("Local 5");
    274 
    275 function local_5(a) {
    276   {
    277     let x = 5;
    278     debugger;
    279   }
    280 }
    281 
    282 listener_delegate = function(exec_state) {
    283   CheckScopeChain([debug.ScopeType.Block,
    284                    debug.ScopeType.Local,
    285                    debug.ScopeType.Script,
    286                    debug.ScopeType.Global], exec_state);
    287   CheckScopeContent({x:5}, 0, exec_state);
    288   CheckScopeContent({a:1}, 1, exec_state);
    289 };
    290 local_5(1);
    291 EndTest();
    292 
    293 
    294 // Two variables in a block scope.
    295 BeginTest("Local 6");
    296 
    297 function local_6(a) {
    298   {
    299     let x = 6;
    300     let y = 7;
    301     debugger;
    302   }
    303 }
    304 
    305 listener_delegate = function(exec_state) {
    306   CheckScopeChain([debug.ScopeType.Block,
    307                    debug.ScopeType.Local,
    308                    debug.ScopeType.Script,
    309                    debug.ScopeType.Global], exec_state);
    310   CheckScopeContent({x:6,y:7}, 0, exec_state);
    311   CheckScopeContent({a:1}, 1, exec_state);
    312 };
    313 local_6(1);
    314 EndTest();
    315 
    316 
    317 // Two variables in a block scope.
    318 BeginTest("Local 7");
    319 
    320 function local_7(a) {
    321   {
    322     {
    323       let x = 8;
    324       debugger;
    325     }
    326   }
    327 }
    328 
    329 listener_delegate = function(exec_state) {
    330   CheckScopeChain([debug.ScopeType.Block,
    331                    debug.ScopeType.Local,
    332                    debug.ScopeType.Script,
    333                    debug.ScopeType.Global], exec_state);
    334   CheckScopeContent({x:8}, 0, exec_state);
    335   CheckScopeContent({a:1}, 1, exec_state);
    336 };
    337 local_7(1);
    338 EndTest();
    339 
    340 
    341 // Simple closure formed by returning an inner function referering to an outer
    342 // block local variable and an outer function's parameter.
    343 BeginTest("Closure 1");
    344 
    345 function closure_1(a) {
    346   var x = 2;
    347   let y = 3;
    348   if (true) {
    349     let z = 4;
    350     function f() {
    351       debugger;
    352       return a + x + y + z;
    353     };
    354     return f;
    355   }
    356 }
    357 
    358 listener_delegate = function(exec_state) {
    359   CheckScopeChain([debug.ScopeType.Local,
    360                    debug.ScopeType.Block,
    361                    debug.ScopeType.Closure,
    362                    debug.ScopeType.Script,
    363                    debug.ScopeType.Global], exec_state);
    364   CheckScopeContent({}, 0, exec_state);
    365   CheckScopeContent({a:1,x:2,y:3}, 2, exec_state);
    366 };
    367 closure_1(1)();
    368 EndTest();
    369 
    370 
    371 // Simple for-in loop over the keys of an object.
    372 BeginTest("For loop 1");
    373 
    374 function for_loop_1() {
    375   for (let x in {y:undefined}) {
    376     debugger;
    377   }
    378 }
    379 
    380 listener_delegate = function(exec_state) {
    381   CheckScopeChain([debug.ScopeType.Block,
    382                    debug.ScopeType.Local,
    383                    debug.ScopeType.Script,
    384                    debug.ScopeType.Global], exec_state);
    385   CheckScopeContent({x:'y'}, 0, exec_state);
    386   // The function scope contains a temporary iteration variable, but it is
    387   // hidden to the debugger.
    388 };
    389 for_loop_1();
    390 EndTest();
    391 
    392 
    393 // For-in loop over the keys of an object with a block scoped let variable
    394 // shadowing the iteration variable.
    395 BeginTest("For loop 2");
    396 
    397 function for_loop_2() {
    398   for (let x in {y:undefined}) {
    399     let x = 3;
    400     debugger;
    401   }
    402 }
    403 
    404 listener_delegate = function(exec_state) {
    405   CheckScopeChain([debug.ScopeType.Block,
    406                    debug.ScopeType.Block,
    407                    debug.ScopeType.Local,
    408                    debug.ScopeType.Script,
    409                    debug.ScopeType.Global], exec_state);
    410   CheckScopeContent({x:3}, 0, exec_state);
    411   CheckScopeContent({x:'y'}, 1, exec_state);
    412   // The function scope contains a temporary iteration variable, hidden to the
    413   // debugger.
    414 };
    415 for_loop_2();
    416 EndTest();
    417 
    418 
    419 // Simple for loop.
    420 BeginTest("For loop 3");
    421 
    422 function for_loop_3() {
    423   for (let x = 3; x < 4; ++x) {
    424     debugger;
    425   }
    426 }
    427 
    428 listener_delegate = function(exec_state) {
    429   CheckScopeChain([debug.ScopeType.Block,
    430                    debug.ScopeType.Local,
    431                    debug.ScopeType.Script,
    432                    debug.ScopeType.Global], exec_state);
    433   CheckScopeContent({x:3}, 0, exec_state);
    434   CheckScopeContent({}, 1, exec_state);
    435 };
    436 for_loop_3();
    437 EndTest();
    438 
    439 
    440 // For loop with a block scoped let variable shadowing the iteration variable.
    441 BeginTest("For loop 4");
    442 
    443 function for_loop_4() {
    444   for (let x = 3; x < 4; ++x) {
    445     let x = 5;
    446     debugger;
    447   }
    448 }
    449 
    450 listener_delegate = function(exec_state) {
    451   CheckScopeChain([debug.ScopeType.Block,
    452                    debug.ScopeType.Block,
    453                    debug.ScopeType.Local,
    454                    debug.ScopeType.Script,
    455                    debug.ScopeType.Global], exec_state);
    456   CheckScopeContent({x:5}, 0, exec_state);
    457   CheckScopeContent({x:3}, 1, exec_state);
    458   CheckScopeContent({}, 2, exec_state);
    459 };
    460 for_loop_4();
    461 EndTest();
    462 
    463 
    464 // For loop with two variable declarations.
    465 BeginTest("For loop 5");
    466 
    467 function for_loop_5() {
    468   for (let x = 3, y = 5; x < 4; ++x) {
    469     debugger;
    470   }
    471 }
    472 
    473 listener_delegate = function(exec_state) {
    474   CheckScopeChain([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({}, 1, exec_state);
    480 };
    481 for_loop_5();
    482 EndTest();
    483 
    484 
    485 // Uninitialized variables
    486 BeginTest("Uninitialized 1");
    487 
    488 function uninitialized_1() {
    489   {
    490     debugger;
    491     let x = 1;
    492   }
    493 }
    494 
    495 listener_delegate = function(exec_state) {
    496   CheckScopeChain([debug.ScopeType.Block,
    497                    debug.ScopeType.Local,
    498                    debug.ScopeType.Script,
    499                    debug.ScopeType.Global], exec_state);
    500   CheckScopeContent({x:undefined}, 0, exec_state);
    501 };
    502 uninitialized_1();
    503 EndTest();
    504 
    505 
    506 // Block scopes shadowing
    507 BeginTest("Block scopes shadowing 1");
    508 function shadowing_1() {
    509   let i = 0;
    510   {
    511     let i = 5;
    512     debugger;
    513   }
    514   assertEquals(0, i);
    515 }
    516 
    517 listener_delegate = function (exec_state) {
    518   assertEqualsUnlessOptimized(5, exec_state.frame(0).evaluate("i").value());
    519 }
    520 shadowing_1();
    521 EndTest();
    522 
    523 
    524 // Block scopes shadowing
    525 BeginTest("Block scopes shadowing 2");
    526 function shadowing_2() {
    527   let i = 0;
    528   {
    529     let j = 5;
    530     debugger;
    531   }
    532 }
    533 
    534 listener_delegate = function (exec_state) {
    535   assertEqualsUnlessOptimized(0, exec_state.frame(0).evaluate("i").value());
    536   assertEqualsUnlessOptimized(5, exec_state.frame(0).evaluate("j").value());
    537 }
    538 shadowing_2();
    539 EndTest();
    540