mirror of https://github.com/lukechilds/node.git
Browse Source
Issue 2399 part 1: In debugger allow modifying local variable values Issue 2399 part 2: In debugger allow modifying local variable values Review URL: https://codereview.chromium.org/11415042 Review URL: https://codereview.chromium.org/11412310 This is a back-port of upstream svn commits r13122 and r13202.v0.10.12-release
7 changed files with 610 additions and 11 deletions
@ -0,0 +1,276 @@ |
|||
// Copyright 2012 the V8 project authors. All rights reserved.
|
|||
// Redistribution and use in source and binary forms, with or without
|
|||
// modification, are permitted provided that the following conditions are
|
|||
// met:
|
|||
//
|
|||
// * Redistributions of source code must retain the above copyright
|
|||
// notice, this list of conditions and the following disclaimer.
|
|||
// * Redistributions in binary form must reproduce the above
|
|||
// copyright notice, this list of conditions and the following
|
|||
// disclaimer in the documentation and/or other materials provided
|
|||
// with the distribution.
|
|||
// * Neither the name of Google Inc. nor the names of its
|
|||
// contributors may be used to endorse or promote products derived
|
|||
// from this software without specific prior written permission.
|
|||
//
|
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
// Flags: --expose-debug-as debug
|
|||
|
|||
// Get the Debug object exposed from the debug context global object.
|
|||
var Debug = debug.Debug; |
|||
|
|||
// Accepts a function/closure 'fun' that must have a debugger statement inside.
|
|||
// A variable 'variable_name' must be initialized before debugger statement
|
|||
// and returned after the statement. The test will alter variable value when
|
|||
// on debugger statement and check that returned value reflects the change.
|
|||
function RunPauseTest(scope_number, expected_old_result, variable_name, |
|||
new_value, expected_new_result, fun) { |
|||
var actual_old_result = fun(); |
|||
assertEquals(expected_old_result, actual_old_result); |
|||
|
|||
var listener_delegate; |
|||
var listener_called = false; |
|||
var exception = null; |
|||
|
|||
function listener_delegate(exec_state) { |
|||
var scope = exec_state.frame(0).scope(scope_number); |
|||
scope.setVariableValue(variable_name, new_value); |
|||
} |
|||
|
|||
function listener(event, exec_state, event_data, data) { |
|||
try { |
|||
if (event == Debug.DebugEvent.Break) { |
|||
listener_called = true; |
|||
listener_delegate(exec_state); |
|||
} |
|||
} catch (e) { |
|||
exception = e; |
|||
} |
|||
} |
|||
|
|||
// Add the debug event listener.
|
|||
Debug.setListener(listener); |
|||
|
|||
var actual_new_value; |
|||
try { |
|||
actual_new_result = fun(); |
|||
} finally { |
|||
Debug.setListener(null); |
|||
} |
|||
|
|||
if (exception != null) { |
|||
assertUnreachable("Exception in listener\n" + exception.stack); |
|||
} |
|||
assertTrue(listener_called); |
|||
|
|||
assertEquals(expected_new_result, actual_new_result); |
|||
} |
|||
|
|||
// Accepts a closure 'fun' that returns a variable from it's outer scope.
|
|||
// The test changes the value of variable via the handle to function and checks
|
|||
// that the return value changed accordingly.
|
|||
function RunClosureTest(scope_number, expected_old_result, variable_name, |
|||
new_value, expected_new_result, fun) { |
|||
var actual_old_result = fun(); |
|||
assertEquals(expected_old_result, actual_old_result); |
|||
|
|||
var fun_mirror = Debug.MakeMirror(fun); |
|||
|
|||
var scope = fun_mirror.scope(scope_number); |
|||
scope.setVariableValue(variable_name, new_value); |
|||
|
|||
var actual_new_result = fun(); |
|||
|
|||
assertEquals(expected_new_result, actual_new_result); |
|||
} |
|||
|
|||
|
|||
function ClosureTestCase(scope_index, old_result, variable_name, new_value, |
|||
new_result, success_expected, factory) { |
|||
this.scope_index_ = scope_index; |
|||
this.old_result_ = old_result; |
|||
this.variable_name_ = variable_name; |
|||
this.new_value_ = new_value; |
|||
this.new_result_ = new_result; |
|||
this.success_expected_ = success_expected; |
|||
this.factory_ = factory; |
|||
} |
|||
|
|||
ClosureTestCase.prototype.run_pause_test = function() { |
|||
var th = this; |
|||
var fun = this.factory_(true); |
|||
this.run_and_catch_(function() { |
|||
RunPauseTest(th.scope_index_ + 1, th.old_result_, th.variable_name_, |
|||
th.new_value_, th.new_result_, fun); |
|||
}); |
|||
} |
|||
|
|||
ClosureTestCase.prototype.run_closure_test = function() { |
|||
var th = this; |
|||
var fun = this.factory_(false); |
|||
this.run_and_catch_(function() { |
|||
RunClosureTest(th.scope_index_, th.old_result_, th.variable_name_, |
|||
th.new_value_, th.new_result_, fun); |
|||
}); |
|||
} |
|||
|
|||
ClosureTestCase.prototype.run_and_catch_ = function(runnable) { |
|||
if (this.success_expected_) { |
|||
runnable(); |
|||
} else { |
|||
assertThrows(runnable); |
|||
} |
|||
} |
|||
|
|||
|
|||
// Test scopes visible from closures.
|
|||
|
|||
var closure_test_cases = [ |
|||
new ClosureTestCase(0, 'cat', 'v1', 5, 5, true, |
|||
function Factory(debug_stop) { |
|||
var v1 = 'cat'; |
|||
return function() { |
|||
if (debug_stop) debugger; |
|||
return v1; |
|||
} |
|||
}), |
|||
|
|||
new ClosureTestCase(0, 4, 't', 7, 9, true, function Factory(debug_stop) { |
|||
var t = 2; |
|||
var r = eval("t"); |
|||
return function() { |
|||
if (debug_stop) debugger; |
|||
return r + t; |
|||
} |
|||
}), |
|||
|
|||
new ClosureTestCase(0, 6, 't', 10, 13, true, function Factory(debug_stop) { |
|||
var t = 2; |
|||
var r = eval("t = 3"); |
|||
return function() { |
|||
if (debug_stop) debugger; |
|||
return r + t; |
|||
} |
|||
}), |
|||
|
|||
new ClosureTestCase(0, 17, 's', 'Bird', 'Bird', true, |
|||
function Factory(debug_stop) { |
|||
eval("var s = 17"); |
|||
return function() { |
|||
if (debug_stop) debugger; |
|||
return s; |
|||
} |
|||
}), |
|||
|
|||
new ClosureTestCase(2, 'capybara', 'foo', 77, 77, true, |
|||
function Factory(debug_stop) { |
|||
var foo = "capybara"; |
|||
return (function() { |
|||
var bar = "fish"; |
|||
try { |
|||
throw {name: "test exception"}; |
|||
} catch (e) { |
|||
return function() { |
|||
if (debug_stop) debugger; |
|||
bar = "beast"; |
|||
return foo; |
|||
} |
|||
} |
|||
})(); |
|||
}), |
|||
|
|||
new ClosureTestCase(0, 'AlphaBeta', 'eee', 5, '5Beta', true, |
|||
function Factory(debug_stop) { |
|||
var foo = "Beta"; |
|||
return (function() { |
|||
var bar = "fish"; |
|||
try { |
|||
throw "Alpha"; |
|||
} catch (eee) { |
|||
return function() { |
|||
if (debug_stop) debugger; |
|||
return eee + foo; |
|||
} |
|||
} |
|||
})(); |
|||
}) |
|||
]; |
|||
|
|||
for (var i = 0; i < closure_test_cases.length; i++) { |
|||
closure_test_cases[i].run_pause_test(); |
|||
} |
|||
|
|||
for (var i = 0; i < closure_test_cases.length; i++) { |
|||
closure_test_cases[i].run_closure_test(); |
|||
} |
|||
|
|||
|
|||
// Test local scope.
|
|||
|
|||
RunPauseTest(0, 'HelloYou', 'u', 'We', 'HelloWe', (function Factory() { |
|||
return function() { |
|||
var u = "You"; |
|||
var v = "Hello"; |
|||
debugger; |
|||
return v + u; |
|||
} |
|||
})()); |
|||
|
|||
RunPauseTest(0, 'Helloworld', 'p', 'GoodBye', 'HelloGoodBye', |
|||
(function Factory() { |
|||
function H(p) { |
|||
var v = "Hello"; |
|||
debugger; |
|||
return v + p; |
|||
} |
|||
return function() { |
|||
return H("world"); |
|||
} |
|||
})()); |
|||
|
|||
RunPauseTest(0, 'mouse', 'v1', 'dog', 'dog', (function Factory() { |
|||
return function() { |
|||
var v1 = 'cat'; |
|||
eval("v1 = 'mouse'"); |
|||
debugger; |
|||
return v1; |
|||
} |
|||
})()); |
|||
|
|||
RunPauseTest(0, 'mouse', 'v1', 'dog', 'dog', (function Factory() { |
|||
return function() { |
|||
eval("var v1 = 'mouse'"); |
|||
debugger; |
|||
return v1; |
|||
} |
|||
})()); |
|||
|
|||
|
|||
// Test value description protocol JSON
|
|||
|
|||
assertEquals(true, Debug.TestApi.CommandProcessorResolveValue({value: true})); |
|||
|
|||
assertSame(null, Debug.TestApi.CommandProcessorResolveValue({type: "null"})); |
|||
assertSame(undefined, |
|||
Debug.TestApi.CommandProcessorResolveValue({type: "undefined"})); |
|||
|
|||
assertSame("123", Debug.TestApi.CommandProcessorResolveValue( |
|||
{type: "string", stringDescription: "123"})); |
|||
assertSame(123, Debug.TestApi.CommandProcessorResolveValue( |
|||
{type: "number", stringDescription: "123"})); |
|||
|
|||
assertSame(Number, Debug.TestApi.CommandProcessorResolveValue( |
|||
{handle: Debug.MakeMirror(Number).handle()})); |
|||
assertSame(RunClosureTest, Debug.TestApi.CommandProcessorResolveValue( |
|||
{handle: Debug.MakeMirror(RunClosureTest).handle()})); |
Loading…
Reference in new issue