blob: 536e71bbb58a33a5ad6e2db9bae34fc9e6034a7f [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 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
28function testMethodNameInference() {
29 function Foo() { }
30 Foo.prototype.bar = function () { FAIL; };
31 (new Foo).bar();
32}
33
34function testNested() {
35 function one() {
36 function two() {
37 function three() {
38 FAIL;
39 }
40 three();
41 }
42 two();
43 }
44 one();
45}
46
47function testArrayNative() {
48 [1, 2, 3].map(function () { FAIL; });
49}
50
51function testImplicitConversion() {
52 function Nirk() { }
53 Nirk.prototype.valueOf = function () { FAIL; };
54 return 1 + (new Nirk);
55}
56
57function testEval() {
58 eval("function Doo() { FAIL; }; Doo();");
59}
60
61function testNestedEval() {
62 var x = "FAIL";
63 eval("function Outer() { eval('function Inner() { eval(x); }'); Inner(); }; Outer();");
64}
65
Kristian Monsen0d5e1162010-09-30 15:31:59 +010066function testEvalWithSourceURL() {
67 eval("function Doo() { FAIL; }; Doo();\n//@ sourceURL=res://name");
68}
69
70function testNestedEvalWithSourceURL() {
71 var x = "FAIL";
72 var innerEval = 'function Inner() { eval(x); }\n//@ sourceURL=res://inner-eval';
73 eval("function Outer() { eval(innerEval); Inner(); }; Outer();\n//@ sourceURL=res://outer-eval");
74}
75
Steve Blocka7e24c12009-10-30 11:49:00 +000076function testValue() {
77 Number.prototype.causeError = function () { FAIL; };
78 (1).causeError();
79}
80
81function testConstructor() {
82 function Plonk() { FAIL; }
83 new Plonk();
84}
85
86function testRenamedMethod() {
87 function a$b$c$d() { return FAIL; }
88 function Wookie() { }
89 Wookie.prototype.d = a$b$c$d;
90 (new Wookie).d();
91}
92
93function testAnonymousMethod() {
94 (function () { FAIL }).call([1, 2, 3]);
95}
96
97function CustomError(message, stripPoint) {
98 this.message = message;
99 Error.captureStackTrace(this, stripPoint);
100}
101
102CustomError.prototype.toString = function () {
103 return "CustomError: " + this.message;
104};
105
106function testDefaultCustomError() {
107 throw new CustomError("hep-hey", undefined);
108}
109
110function testStrippedCustomError() {
111 throw new CustomError("hep-hey", CustomError);
112}
113
114// Utility function for testing that the expected strings occur
115// in the stack trace produced when running the given function.
116function testTrace(name, fun, expected, unexpected) {
117 var threw = false;
118 try {
119 fun();
120 } catch (e) {
121 for (var i = 0; i < expected.length; i++) {
122 assertTrue(e.stack.indexOf(expected[i]) != -1,
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100123 name + " doesn't contain expected[" + i + "] stack = " + e.stack);
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 }
125 if (unexpected) {
126 for (var i = 0; i < unexpected.length; i++) {
127 assertEquals(e.stack.indexOf(unexpected[i]), -1,
128 name + " contains unexpected[" + i + "]");
129 }
130 }
131 threw = true;
132 }
133 assertTrue(threw, name + " didn't throw");
134}
135
136// Test that the error constructor is not shown in the trace
137function testCallerCensorship() {
138 var threw = false;
139 try {
140 FAIL;
141 } catch (e) {
142 assertEquals(-1, e.stack.indexOf('at new ReferenceError'),
143 "CallerCensorship contained new ReferenceError");
144 threw = true;
145 }
146 assertTrue(threw, "CallerCensorship didn't throw");
147}
148
149// Test that the explicit constructor call is shown in the trace
150function testUnintendedCallerCensorship() {
151 var threw = false;
152 try {
153 new ReferenceError({
154 toString: function () {
155 FAIL;
156 }
157 });
158 } catch (e) {
159 assertTrue(e.stack.indexOf('at new ReferenceError') != -1,
160 "UnintendedCallerCensorship didn't contain new ReferenceError");
161 threw = true;
162 }
163 assertTrue(threw, "UnintendedCallerCensorship didn't throw");
164}
165
166// If an error occurs while the stack trace is being formatted it should
167// be handled gracefully.
168function testErrorsDuringFormatting() {
169 function Nasty() { }
170 Nasty.prototype.foo = function () { throw new RangeError(); };
171 var n = new Nasty();
172 n.__defineGetter__('constructor', function () { CONS_FAIL; });
173 var threw = false;
174 try {
175 n.foo();
176 } catch (e) {
177 threw = true;
178 assertTrue(e.stack.indexOf('<error: ReferenceError') != -1,
179 "ErrorsDuringFormatting didn't contain error: ReferenceError");
180 }
181 assertTrue(threw, "ErrorsDuringFormatting didn't throw");
182 threw = false;
183 // Now we can't even format the message saying that we couldn't format
184 // the stack frame. Put that in your pipe and smoke it!
185 ReferenceError.prototype.toString = function () { NESTED_FAIL; };
186 try {
187 n.foo();
188 } catch (e) {
189 threw = true;
190 assertTrue(e.stack.indexOf('<error>') != -1,
191 "ErrorsDuringFormatting didn't contain <error>");
192 }
193 assertTrue(threw, "ErrorsDuringFormatting didnt' throw (2)");
194}
195
196
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100197// Poisonous object that throws a reference error if attempted converted to
198// a primitive values.
199var thrower = { valueOf: function() { FAIL; },
200 toString: function() { FAIL; } };
201
202// Tests that a native constructor function is included in the
203// stack trace.
204function testTraceNativeConstructor(nativeFunc) {
205 var nativeFuncName = nativeFunc.name;
206 try {
207 new nativeFunc(thrower);
208 assertUnreachable(nativeFuncName);
209 } catch (e) {
210 assertTrue(e.stack.indexOf(nativeFuncName) >= 0, nativeFuncName);
211 }
212}
213
214// Tests that a native conversion function is included in the
215// stack trace.
216function testTraceNativeConversion(nativeFunc) {
217 var nativeFuncName = nativeFunc.name;
218 try {
219 nativeFunc(thrower);
220 assertUnreachable(nativeFuncName);
221 } catch (e) {
222 assertTrue(e.stack.indexOf(nativeFuncName) >= 0, nativeFuncName);
223 }
224}
225
226
227function testOmittedBuiltin(throwing, omitted) {
228 try {
229 throwing();
230 assertUnreachable(omitted);
231 } catch (e) {
232 assertTrue(e.stack.indexOf(omitted) < 0, omitted);
233 }
234}
235
236
Steve Blocka7e24c12009-10-30 11:49:00 +0000237testTrace("testArrayNative", testArrayNative, ["Array.map (native)"]);
238testTrace("testNested", testNested, ["at one", "at two", "at three"]);
239testTrace("testMethodNameInference", testMethodNameInference, ["at Foo.bar"]);
240testTrace("testImplicitConversion", testImplicitConversion, ["at Nirk.valueOf"]);
241testTrace("testEval", testEval, ["at Doo (eval at testEval"]);
242testTrace("testNestedEval", testNestedEval, ["eval at Inner (eval at Outer"]);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100243testTrace("testEvalWithSourceURL", testEvalWithSourceURL,
244 [ "at Doo (res://name:1:18)" ]);
245testTrace("testNestedEvalWithSourceURL", testNestedEvalWithSourceURL,
246 [" at Inner (res://inner-eval:1:20)",
247 " at Outer (res://outer-eval:1:37)"]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000248testTrace("testValue", testValue, ["at Number.causeError"]);
249testTrace("testConstructor", testConstructor, ["new Plonk"]);
250testTrace("testRenamedMethod", testRenamedMethod, ["Wookie.a$b$c$d [as d]"]);
251testTrace("testAnonymousMethod", testAnonymousMethod, ["Array.<anonymous>"]);
252testTrace("testDefaultCustomError", testDefaultCustomError,
253 ["hep-hey", "new CustomError"],
254 ["collectStackTrace"]);
255testTrace("testStrippedCustomError", testStrippedCustomError, ["hep-hey"],
256 ["new CustomError", "collectStackTrace"]);
257testCallerCensorship();
258testUnintendedCallerCensorship();
259testErrorsDuringFormatting();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100260
261testTraceNativeConversion(String); // Does ToString on argument.
262testTraceNativeConversion(Number); // Does ToNumber on argument.
263testTraceNativeConversion(RegExp); // Does ToString on argument.
264
265testTraceNativeConstructor(String); // Does ToString on argument.
266testTraceNativeConstructor(Number); // Does ToNumber on argument.
267testTraceNativeConstructor(RegExp); // Does ToString on argument.
268testTraceNativeConstructor(Date); // Does ToNumber on argument.
269
270// Omitted because QuickSort has builtins object as receiver, and is non-native
271// builtin.
272testOmittedBuiltin(function(){ [thrower, 2].sort(function (a,b) {
273 (b < a) - (a < b); });
274 }, "QuickSort");
275
276// Omitted because ADD from runtime.js is non-native builtin.
277testOmittedBuiltin(function(){ thrower + 2; }, "ADD");