Environment-variables.js (3035B)
1 // Comprehensive test of get/setVariable on many kinds of environments and 2 // bindings. 3 4 load(libdir + "asserts.js"); 5 6 var cases = [ 7 // global bindings and bindings on the global prototype chain 8 "x = VAL; @@", 9 "var x = VAL; @@", 10 "Object.prototype.x = VAL; @@", 11 12 // let and catch bindings 13 "let x = VAL; @@", 14 "{ let x = VAL; @@ }", 15 "try { throw VAL; } catch (x) { @@ }", 16 "try { throw VAL; } catch (x) { @@ }", 17 "for (let x of [VAL]) { @@ }", 18 "switch (0) { default: let x = VAL; @@ }", 19 20 // arguments 21 "function f(x) { @@ } f(VAL);", 22 "function f([w, x]) { @@ } f([0, VAL]);", 23 "function f({v: x}) { @@ } f({v: VAL});", 24 "function f([w, {v: x}]) { @@ } f([0, {v: VAL}]);", 25 26 // bindings in functions 27 "function f() { var x = VAL; @@ } f();", 28 "function f() { let x = VAL; @@ } f();", 29 "function f() { function x() {} x = VAL; @@ } f();", 30 31 // dynamic bindings 32 "function f(s) { eval(s); @@ } f('var x = VAL');", 33 "var x = VAL; function f(s) { eval('var x = 0;'); eval(s); @@ } f('delete x;');", 34 "function f(obj) { with (obj) { @@ } } f({x: VAL});", 35 "function f(obj) { with (obj) { @@ } } f(Object.create({x: VAL}));", 36 "function f(b) { if (b) { function x(){} } x = VAL; @@ } f(1);", 37 ]; 38 39 var nextval = 1000; 40 41 function test(code, debugStmts, followupStmts) { 42 var val = nextval++; 43 var hits = 0; 44 45 var g = newGlobal({newCompartment: true}); 46 g.eval("function debugMe() { var x = 'wrong-x'; eval(\"\"); debugger; }"); 47 g.capture = null; 48 49 var dbg = Debugger(g); 50 dbg.onDebuggerStatement = function (frame) { 51 if (frame.callee !== null && frame.callee.name == 'debugMe') 52 frame = frame.older; 53 var env = frame.environment.find("x"); 54 assertEq(env.getVariable("x"), val) 55 assertEq(env.setVariable("x", 'ok'), undefined); 56 assertEq(env.getVariable("x"), 'ok'); 57 58 // setVariable cannot create new variables. 59 assertThrowsInstanceOf(function () { env.setVariable("newVar", 0); }, TypeError); 60 hits++; 61 }; 62 63 code = code.replace("@@", debugStmts); 64 if (followupStmts !== undefined) 65 code += " " + followupStmts; 66 code = code.replace(/VAL/g, String(val)); 67 g.eval(code); 68 assertEq(hits, 1); 69 } 70 71 for (var s of cases) { 72 // Test triggering the debugger right in the scope in which x is bound. 73 test(s, "eval(\"\"); debugger; assertEq(x, 'ok');"); 74 75 // Test calling a function that triggers the debugger. 76 test(s, "debugMe(); assertEq(x, 'ok');"); 77 78 // Test triggering the debugger from a scope nested in x's scope. 79 test(s, "{ let y = 'irrelevant'; (function (z) { { let zz = y; eval(\"\"); debugger; } })(); } assertEq(x, 'ok');"), 80 81 // Test closing over the variable and triggering the debugger later, after 82 // leaving the variable's scope. 83 test(s, "capture = {dbg: function () { eval(\"\"); debugger; }, get x() { return x; }};", 84 "assertEq(capture.x, VAL); capture.dbg(); assertEq(capture.x, 'ok');"); 85 }