| // 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. |
| |
| // Return the stack frames of an Error object. |
| |
| Error.prepareStackTrace = function(error, frames) { |
| return frames; |
| } |
| |
| Error.prototype.getFrames = function() { |
| var frames = this.stack; |
| return frames; |
| } |
| |
| String.prototype.contains = function(pattern) { |
| return this.indexOf(pattern) > -1; |
| } |
| |
| // Check for every frame that a certain method returns the |
| // expected value for every frame. |
| Array.prototype.verifyEquals = function(frames, func_name) { |
| this.forEach( |
| function(element, index) { |
| var frame = frames[index]; |
| if (element === null) return; |
| assertEquals(element, (frame[func_name])()); |
| } |
| ); |
| } |
| |
| // Check for every frame that a certain method has a return value |
| // that contains the expected pattern for every frame. |
| Array.prototype.verifyContains = function(frames, func_name) { |
| this.forEach( |
| function(element, index) { |
| var frame = frames[index]; |
| if (element === null) return; |
| assertTrue((frame[func_name])().contains(element)); |
| } |
| ); |
| } |
| |
| // Check for every frame that a certain method returns undefined |
| // when expected. |
| Array.prototype.verifyUndefined = function(frames, func_name) { |
| this.forEach( |
| function(element, index) { |
| var frame = frames[index]; |
| if (element === null) return; |
| assertEquals(element, (frame[func_name])() === undefined); |
| } |
| ); |
| } |
| |
| |
| // Simple eval. |
| var code1 = "function f() { \n" + |
| " throw new Error(3); \n" + // Line 2 |
| "} \n" + |
| "f(); \n"; // Line 4 |
| |
| function g() { |
| eval(code1); |
| } |
| |
| try { |
| g(); |
| } catch (e) { |
| // We expect something like |
| // f (eval at g (eval-stack.js:87:8), <anonymous>:2:9) |
| // eval (eval at g (eval-stack.js:87:8), <anonymous>:4:1) |
| // g (eval-stack.js:87:3) |
| // eval-stack.js:94:3 |
| var frames = e.getFrames(); |
| assertEquals(4, frames.length); |
| ["f", "eval", "g"] |
| .verifyEquals(frames, "getFunctionName"); |
| [2, 4] |
| .verifyEquals(frames, "getLineNumber"); |
| ["<anonymous>:2:", "<anonymous>:4:"] |
| .verifyContains(frames, "toString"); |
| [true, true, false, false] |
| .verifyUndefined(frames, "getFileName"); |
| ["eval at g", "eval at g"] |
| .verifyContains(frames, "getEvalOrigin"); |
| } |
| |
| |
| // Nested eval. |
| var code2 = "function h() { \n" + |
| " // Empty \n" + |
| " eval(code1); \n" + // Line 3 |
| "} \n" + |
| "h(); \n"; // Line 5 |
| |
| try { |
| eval(code2); |
| } catch (e) { |
| // We expect something like |
| // f (eval at h (eval at <anonymous> (eval-stack.js:116:8)), |
| // <anonymous>:2:9) |
| // eval (eval at h (eval at <anonymous> (eval-stack.js:116:8)), |
| // <anonymous>:4:1) |
| // h (eval at <anonymous> (eval-stack.js:116:8), <anonymous>:3:3) |
| // eval (eval at <anonymous> (eval-stack.js:116:8), <anonymous>:5:1) |
| // eval-stack.js:116:3 |
| var frames = e.getFrames(); |
| assertEquals(5, frames.length); |
| ["f", "eval", "h", "eval"] |
| .verifyEquals(frames, "getFunctionName"); |
| [2, 4, 3, 5] |
| .verifyEquals(frames, "getLineNumber"); |
| ["<anonymous>:2:", "<anonymous>:4:", "<anonymous>:3:", "<anonymous>:5:"] |
| .verifyContains(frames, "toString"); |
| [true, true, true, true, false] |
| .verifyUndefined(frames, "getFileName"); |
| ["eval at h (eval at <anonymous> (", |
| "eval at h (eval at <anonymous> (", |
| "eval at <anonymous> (", |
| "eval at <anonymous> ("] |
| .verifyContains(frames, "getEvalOrigin"); |
| } |
| |
| |
| // Nested eval calling through non-eval defined function. |
| var code3 = "function h() { \n" + |
| " // Empty \n" + |
| " g(); \n" + // Line 3 |
| "} \n" + |
| "h(); \n"; // Line 5 |
| |
| try { |
| eval(code3); |
| } catch (e) { |
| // We expect something like |
| // f (eval at g (test.js:83:8), <anonymous>:2:9) |
| // eval (eval at g (test.js:83:8), <anonymous>:4:1) |
| // g (test.js:83:3) |
| // h (eval at <anonymous> (test.js:149:8), <anonymous>:3:3) |
| // eval (eval at <anonymous> (test.js:149:8), <anonymous>:5:1) |
| // test.js:149:3 |
| var frames = e.getFrames(); |
| assertEquals(6, frames.length); |
| ["f", "eval", "g", "h", "eval"] |
| .verifyEquals(frames, "getFunctionName"); |
| [2, 4, null, 3, 5] |
| .verifyEquals(frames, "getLineNumber"); |
| ["<anonymous>:2:", "<anonymous>:4:", null, "<anonymous>:3:", "<anonymous>:5:"] |
| .verifyContains(frames, "toString"); |
| [true, true, false, true, true, false] |
| .verifyUndefined(frames, "getFileName"); |
| ["eval at g (", |
| "eval at g (", |
| null, |
| "eval at <anonymous> (", |
| "eval at <anonymous> ("] |
| .verifyContains(frames, "getEvalOrigin"); |
| } |
| |
| |
| // Calling function defined in eval. |
| eval("function f() { \n" + |
| " throw new Error(3); \n" + |
| "} \n"); |
| |
| try { |
| f(); |
| } catch (e) { |
| // We expect something like |
| // f (eval at <anonymous> (test.js:182:40), <anonymous>:2:9) |
| // test.js:186:3 |
| var frames = e.getFrames(); |
| assertEquals(2, frames.length); |
| ["f"].verifyEquals(frames, "getFunctionName"); |
| [2].verifyEquals(frames, "getLineNumber"); |
| ["<anonymous>:2:"].verifyContains(frames, "toString"); |
| [true, false].verifyUndefined(frames, "getFileName"); |
| ["eval at <anonymous> ("].verifyContains(frames, "getEvalOrigin"); |
| } |