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 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_value;
     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 it's 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