Home | History | Annotate | Download | only in mjsunit
      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 
     33 // Accepts a function/closure 'fun' that must have a debugger statement inside.
     34 // A variable 'variable_name' must be initialized before debugger statement
     35 // and returned after the statement. The test will alter variable value when
     36 // on debugger statement and check that returned value reflects the change.
     37 function RunPauseTest(scope_number, expected_old_result, variable_name,
     38     new_value, expected_new_result, fun) {
     39   var actual_old_result = fun();
     40   assertEquals(expected_old_result, actual_old_result);
     41 
     42   var listener_delegate;
     43   var listener_called = false;
     44   var exception = null;
     45 
     46   function listener_delegate(exec_state) {
     47     var scope = exec_state.frame(0).scope(scope_number);
     48     scope.setVariableValue(variable_name, new_value);
     49   }
     50 
     51   function listener(event, exec_state, event_data, data) {
     52     try {
     53       if (event == Debug.DebugEvent.Break) {
     54         listener_called = true;
     55         listener_delegate(exec_state);
     56       }
     57     } catch (e) {
     58       exception = e;
     59     }
     60   }
     61 
     62   // Add the debug event listener.
     63   Debug.setListener(listener);
     64 
     65   var actual_new_value;
     66   try {
     67     actual_new_result = fun();
     68   } finally {
     69     Debug.setListener(null);
     70   }
     71 
     72   if (exception != null) {
     73    assertUnreachable("Exception in listener\n" + exception.stack);
     74   }
     75   assertTrue(listener_called);
     76 
     77   assertEquals(expected_new_result, actual_new_result);
     78 }
     79 
     80 // Accepts a closure 'fun' that returns a variable from it's outer scope.
     81 // The test changes the value of variable via the handle to function and checks
     82 // that the return value changed accordingly.
     83 function RunClosureTest(scope_number, expected_old_result, variable_name,
     84     new_value, expected_new_result, fun) {
     85   var actual_old_result = fun();
     86   assertEquals(expected_old_result, actual_old_result);
     87 
     88   var fun_mirror = Debug.MakeMirror(fun);
     89 
     90   var scope = fun_mirror.scope(scope_number);
     91   scope.setVariableValue(variable_name, new_value);
     92 
     93   var actual_new_result = fun();
     94 
     95   assertEquals(expected_new_result, actual_new_result);
     96 }
     97 
     98 
     99 function ClosureTestCase(scope_index, old_result, variable_name, new_value,
    100     new_result, success_expected, factory) {
    101   this.scope_index_ = scope_index;
    102   this.old_result_ = old_result;
    103   this.variable_name_ = variable_name;
    104   this.new_value_ = new_value;
    105   this.new_result_ = new_result;
    106   this.success_expected_ = success_expected;
    107   this.factory_ = factory;
    108 }
    109 
    110 ClosureTestCase.prototype.run_pause_test = function() {
    111   var th = this;
    112   var fun = this.factory_(true);
    113   this.run_and_catch_(function() {
    114     RunPauseTest(th.scope_index_ + 1, th.old_result_, th.variable_name_,
    115         th.new_value_, th.new_result_, fun);
    116   });
    117 }
    118 
    119 ClosureTestCase.prototype.run_closure_test = function() {
    120   var th = this;
    121   var fun = this.factory_(false);
    122   this.run_and_catch_(function() {
    123     RunClosureTest(th.scope_index_, th.old_result_, th.variable_name_,
    124         th.new_value_, th.new_result_, fun);
    125   });
    126 }
    127 
    128 ClosureTestCase.prototype.run_and_catch_ = function(runnable) {
    129   if (this.success_expected_) {
    130     runnable();
    131   } else {
    132     assertThrows(runnable);
    133   }
    134 }
    135 
    136 
    137 // Test scopes visible from closures.
    138 
    139 var closure_test_cases = [
    140   new ClosureTestCase(0, 'cat', 'v1', 5, 5, true,
    141       function Factory(debug_stop) {
    142     var v1 = 'cat';
    143     return function() {
    144       if (debug_stop) debugger;
    145       return v1;
    146     }
    147   }),
    148 
    149   new ClosureTestCase(0, 4, 't', 7, 9, true, function Factory(debug_stop) {
    150     var t = 2;
    151     var r = eval("t");
    152     return function() {
    153       if (debug_stop) debugger;
    154       return r + t;
    155     }
    156   }),
    157 
    158   new ClosureTestCase(0, 6, 't', 10, 13, true, function Factory(debug_stop) {
    159     var t = 2;
    160     var r = eval("t = 3");
    161     return function() {
    162       if (debug_stop) debugger;
    163       return r + t;
    164     }
    165   }),
    166 
    167   new ClosureTestCase(0, 17, 's', 'Bird', 'Bird', true,
    168       function Factory(debug_stop) {
    169     eval("var s = 17");
    170     return function() {
    171       if (debug_stop) debugger;
    172       return s;
    173     }
    174   }),
    175 
    176   new ClosureTestCase(2, 'capybara', 'foo', 77, 77, true,
    177       function Factory(debug_stop) {
    178     var foo = "capybara";
    179     return (function() {
    180       var bar = "fish";
    181       try {
    182         throw {name: "test exception"};
    183       } catch (e) {
    184         return function() {
    185           if (debug_stop) debugger;
    186           bar = "beast";
    187           return foo;
    188         }
    189       }
    190     })();
    191   }),
    192 
    193   new ClosureTestCase(0, 'AlphaBeta', 'eee', 5, '5Beta', true,
    194       function Factory(debug_stop) {
    195     var foo = "Beta";
    196     return (function() {
    197       var bar = "fish";
    198       try {
    199         throw "Alpha";
    200       } catch (eee) {
    201         return function() {
    202           if (debug_stop) debugger;
    203           return eee + foo;
    204         }
    205       }
    206     })();
    207   })
    208 ];
    209 
    210 for (var i = 0; i < closure_test_cases.length; i++) {
    211   closure_test_cases[i].run_pause_test();
    212 }
    213 
    214 for (var i = 0; i < closure_test_cases.length; i++) {
    215   closure_test_cases[i].run_closure_test();
    216 }
    217 
    218 
    219 // Test local scope.
    220 
    221 RunPauseTest(0, 'HelloYou', 'u', 'We', 'HelloWe', (function Factory() {
    222   return function() {
    223     var u = "You";
    224     var v = "Hello";
    225     debugger;
    226     return v + u;
    227   }
    228 })());
    229 
    230 RunPauseTest(0, 'Helloworld', 'p', 'GoodBye', 'HelloGoodBye',
    231     (function Factory() {
    232   function H(p) {
    233     var v = "Hello";
    234     debugger;
    235     return v + p;
    236   }
    237   return function() {
    238     return H("world");
    239   }
    240 })());
    241 
    242 RunPauseTest(0, 'mouse', 'v1', 'dog', 'dog', (function Factory() {
    243   return function() {
    244     var v1 = 'cat';
    245     eval("v1 = 'mouse'");
    246     debugger;
    247     return v1;
    248   }
    249 })());
    250 
    251 RunPauseTest(0, 'mouse', 'v1', 'dog', 'dog', (function Factory() {
    252   return function() {
    253     eval("var v1 = 'mouse'");
    254     debugger;
    255     return v1;
    256   }
    257 })());
    258 
    259 
    260 // Check that we correctly update local variable that
    261 // is referenced from an inner closure.
    262 RunPauseTest(0, 'Blue', 'v', 'Green', 'Green', (function Factory() {
    263   return function() {
    264     function A() {
    265       var v = "Blue";
    266       function Inner() {
    267         return void v;
    268       }
    269       debugger;
    270       return v;
    271     }
    272     return A();
    273   }
    274 })());
    275 
    276 // Check that we correctly update parameter, that is known to be stored
    277 // both on stack and in heap.
    278 RunPauseTest(0, 5, 'p', 2012, 2012, (function Factory() {
    279   return function() {
    280     function A(p) {
    281       function Inner() {
    282         return void p;
    283       }
    284       debugger;
    285       return p;
    286     }
    287     return A(5);
    288   }
    289 })());
    290 
    291 
    292 // Test value description protocol JSON
    293 
    294 assertEquals(true, Debug.TestApi.CommandProcessorResolveValue({value: true}));
    295 
    296 assertSame(null, Debug.TestApi.CommandProcessorResolveValue({type: "null"}));
    297 assertSame(undefined,
    298     Debug.TestApi.CommandProcessorResolveValue({type: "undefined"}));
    299 
    300 assertSame("123", Debug.TestApi.CommandProcessorResolveValue(
    301     {type: "string", stringDescription: "123"}));
    302 assertSame(123, Debug.TestApi.CommandProcessorResolveValue(
    303     {type: "number", stringDescription: "123"}));
    304 
    305 assertSame(Number, Debug.TestApi.CommandProcessorResolveValue(
    306     {handle: Debug.MakeMirror(Number).handle()}));
    307 assertSame(RunClosureTest, Debug.TestApi.CommandProcessorResolveValue(
    308     {handle: Debug.MakeMirror(RunClosureTest).handle()}));
    309