blob: 368ab498548f52b6eddb77c44dcb96f59e9c3ab7 [file] [log] [blame]
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --no-always-opt --no-opt
// The first part of this file is copied over from debug-set-variable-value.js
// (a few tests were removed because they make no sense for modules). The second
// part is new.
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_result;
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);
}
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_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(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();
}
// 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;
}
})());
// Check that we correctly update local variable that
// is referenced from an inner closure.
RunPauseTest(0, 'Blue', 'v', 'Green', 'Green', (function Factory() {
return function() {
function A() {
var v = "Blue";
function Inner() {
return void v;
}
debugger;
return v;
}
return A();
}
})());
// Check that we correctly update parameter, that is known to be stored
// both on stack and in heap.
RunPauseTest(0, 5, 'p', 2012, 2012, (function Factory() {
return function() {
function A(p) {
function Inner() {
return void p;
}
debugger;
return p;
}
return A(5);
}
})());
////////////////////////////////////////////////////////////////////////////////
// From here on we test the module scope.
////////////////////////////////////////////////////////////////////////////////
// Non-existing variable.
{
let exception;
function listener(event, exec_state) {
if (event == Debug.DebugEvent.Break) {
let module_scope = exec_state.frame().scope(1);
assertEquals(debug.ScopeType.Module, module_scope.scopeType());
try {
module_scope.setVariableValue('spargel', 42);
} catch(e) { exception = e; }
}
}
Debug.setListener(listener);
assertThrows(() => spargel, ReferenceError);
debugger;
assertThrows(() => spargel, ReferenceError);
assertTrue(exception !== undefined);
}
// Local (non-exported) variable.
let salat = 12;
{
function listener(event, exec_state) {
if (event == Debug.DebugEvent.Break) {
let module_scope = exec_state.frame().scope(1);
assertEquals(debug.ScopeType.Module, module_scope.scopeType());
module_scope.setVariableValue('salat', 42);
}
}
Debug.setListener(listener);
assertEquals(12, salat);
debugger;
assertEquals(42, salat);
}
// Local (non-exported) variable, nested access.
let salad = 12;
{
function listener(event, exec_state) {
if (event == Debug.DebugEvent.Break) {
let scope_count = exec_state.frame().scopeCount();
let module_scope = exec_state.frame().scope(1);
assertEquals(debug.ScopeType.Module, module_scope.scopeType());
module_scope.setVariableValue('salad', 42);
}
}
Debug.setListener(listener);
function foo() {
assertEquals(12, salad);
debugger;
assertEquals(42, salad);
};
foo();
}
// Exported variable.
export let salami = 1;
{
function listener(event, exec_state) {
if (event == Debug.DebugEvent.Break) {
let module_scope = exec_state.frame().scope(1);
assertEquals(debug.ScopeType.Module, module_scope.scopeType());
module_scope.setVariableValue('salami', 2);
}
}
Debug.setListener(listener);
assertEquals(1, salami);
debugger;
assertEquals(2, salami);
}
// Exported variable, nested access.
export let ham = 1;
{
function listener(event, exec_state) {
if (event == Debug.DebugEvent.Break) {
let scope_count = exec_state.frame().scopeCount();
let module_scope = exec_state.frame().scope(1);
assertEquals(debug.ScopeType.Module, module_scope.scopeType());
module_scope.setVariableValue('ham', 2);
}
}
Debug.setListener(listener);
function foo() {
assertEquals(1, ham);
debugger;
assertEquals(2, ham);
};
foo();
}
// Imported variable. Setting is currently not supported.
import { salami as wurst } from "./debug-modules-set-variable-value.mjs";
{
let exception;
function listener(event, exec_state) {
if (event == Debug.DebugEvent.Break) {
let module_scope = exec_state.frame().scope(1);
assertEquals(debug.ScopeType.Module, module_scope.scopeType());
try {
module_scope.setVariableValue('wurst', 3);
} catch(e) { exception = e; }
}
}
Debug.setListener(listener);
assertEquals(2, wurst);
debugger;
assertEquals(2, wurst);
assertTrue(exception !== undefined);
}
// Imported variable, nested access. Setting is currently not supported.
import { salami as wurstl } from "./debug-modules-set-variable-value.mjs";
{
let exception;
function listener(event, exec_state) {
if (event == Debug.DebugEvent.Break) {
let scope_count = exec_state.frame().scopeCount();
let module_scope = exec_state.frame().scope(2);
assertEquals(debug.ScopeType.Module, module_scope.scopeType());
try {
module_scope.setVariableValue('wurstl', 3);
} catch(e) { exception = e; }
}
}
Debug.setListener(listener);
function foo() {
assertEquals(2, wurstl);
debugger;
assertEquals(2, wurstl);
assertTrue(exception !== undefined);
};
foo();
}
Debug.setListener(null);