diff options
Diffstat (limited to 'js/src/tests/ecma_5/extensions')
62 files changed, 2831 insertions, 0 deletions
diff --git a/js/src/tests/ecma_5/extensions/15.4.4.11.js b/js/src/tests/ecma_5/extensions/15.4.4.11.js new file mode 100644 index 000000000..a4c38faa7 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/15.4.4.11.js @@ -0,0 +1,32 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +function arr() { + return Object.defineProperty([20, 10, 30], 0, {writable: false}); +} + +assertEq(testLenientAndStrict('var a = arr(); a.sort()', + raisesException(TypeError), + raisesException(TypeError)), + true); + +function obj() { + var o = {0: 20, 1: 10, 2: 30, length: 3}; + Object.defineProperty(o, 0, {writable: false}); + return o; +} + +assertEq(testLenientAndStrict('var o = obj(); Array.prototype.sort.call(o)', + raisesException(TypeError), + raisesException(TypeError)), + true); + +// The behavior of sort is implementation-defined if the object being +// sorted is sparse, so I'm not sure how to test its behavior on +// non-configurable properties. + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/15.9.4.2.js b/js/src/tests/ecma_5/extensions/15.9.4.2.js new file mode 100644 index 000000000..c517f8be8 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/15.9.4.2.js @@ -0,0 +1,59 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 682754; + + +//----------------------------------------------------------------------------- +test(); +//----------------------------------------------------------------------------- + +function iso(d) +{ + return new Date(d).toISOString(); +} + +function check(s, millis){ + description = "Date.parse('"+s+"') == '"+iso(millis)+"'"; + expected = millis; + actual = Date.parse(s); + reportCompare(expected, actual, description); +} + +function checkInvalid(s) +{ + description = "Date.parse('"+s+"') produces invalid date"; + expected = NaN; + actual = Date.parse(s); + reportCompare(expected, actual, description); +} + +function dd(year, month, day, hour, minute, second, millis){ + return Date.UTC(year, month-1, day, hour, minute, second, millis); +} + +function TZAtDate(d){ + return d.getTimezoneOffset() * 60000; +} + +function TZInMonth(month){ + return TZAtDate(new Date(dd(2009,month,1,0,0,0,0))); +} + +function test() +{ + enterFunc ('test'); + printBugNumber(BUGNUMBER); + + JanTZ = TZInMonth(1); + JulTZ = TZInMonth(7); + CurrTZ = TZAtDate(new Date()); + + // Allow non-standard "-0700" as timezone, not just "-07:00" + check("2009-07-23T00:53:21.001-0700", dd(2009,7,23,7,53,21,1)); + + exitFunc ('test'); +} diff --git a/js/src/tests/ecma_5/extensions/8.12.5-01.js b/js/src/tests/ecma_5/extensions/8.12.5-01.js new file mode 100644 index 000000000..c6f1c18ee --- /dev/null +++ b/js/src/tests/ecma_5/extensions/8.12.5-01.js @@ -0,0 +1,97 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jason Orendorff + * Jeff Walden <jwalden+code@mit.edu> + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 523846; +var summary = + "Assignments to a property that has a getter but not a setter should not " + + "throw a TypeError per ES5 (at least not until strict mode is supported)"; +var actual = "Early failure"; +var expect = "No errors"; + + +printBugNumber(BUGNUMBER); +printStatus(summary); + +var o = { get p() { return "a"; } }; + +function test1() +{ + o.p = "b"; // strict-mode violation here + assertEq(o.p, "a"); +} + +function test2() +{ + function T() {} + T.prototype = o; + y = new T(); + y.p = "b"; // strict-mode violation here + assertEq(y.p, "a"); +} + + +var errors = []; +try +{ + try + { + test1(); + } + catch (e) + { + errors.push(e); + } + + try + { + test2(); + } + catch (e) + { + errors.push(e); + } + + options("strict"); + options("werror"); + try + { + test1(); + errors.push("strict+werror didn't make test1 fail"); + } + catch (e) + { + if (!(e instanceof TypeError)) + errors.push("test1 with strict+werror failed without a TypeError: " + e); + } + + try + { + test2(); + errors.push("strict+werror didn't make test2 fail"); + } + catch (e) + { + if (!(e instanceof TypeError)) + errors.push("test2 with strict+werror failed without a TypeError: " + e); + } + + options("strict"); + options("werror"); +} +catch (e) +{ + errors.push("Unexpected error: " + e); +} +finally +{ + actual = errors.length > 0 ? errors.join(", ") : "No errors"; +} + +reportCompare(expect, actual, summary); diff --git a/js/src/tests/ecma_5/extensions/Boolean-toSource.js b/js/src/tests/ecma_5/extensions/Boolean-toSource.js new file mode 100644 index 000000000..8d135a9fd --- /dev/null +++ b/js/src/tests/ecma_5/extensions/Boolean-toSource.js @@ -0,0 +1,17 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +assertEq(raisesException(TypeError)('Boolean.prototype.toSource.call(42)'), true); +assertEq(raisesException(TypeError)('Boolean.prototype.toSource.call("")'), true); +assertEq(raisesException(TypeError)('Boolean.prototype.toSource.call({})'), true); +assertEq(raisesException(TypeError)('Boolean.prototype.toSource.call(null)'), true); +assertEq(raisesException(TypeError)('Boolean.prototype.toSource.call([])'), true); +assertEq(raisesException(TypeError)('Boolean.prototype.toSource.call(undefined)'), true); +assertEq(raisesException(TypeError)('Boolean.prototype.toSource.call(new String())'), true); + +assertEq(completesNormally('Boolean.prototype.toSource.call(true)'), true); +assertEq(completesNormally('Boolean.prototype.toSource.call(new Boolean(true))'), true); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/Number-toSource.js b/js/src/tests/ecma_5/extensions/Number-toSource.js new file mode 100644 index 000000000..c2e306f53 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/Number-toSource.js @@ -0,0 +1,17 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +assertEq(raisesException(TypeError)('Number.prototype.toSource.call("")'), true); +assertEq(raisesException(TypeError)('Number.prototype.toSource.call(true)'), true); +assertEq(raisesException(TypeError)('Number.prototype.toSource.call({})'), true); +assertEq(raisesException(TypeError)('Number.prototype.toSource.call(null)'), true); +assertEq(raisesException(TypeError)('Number.prototype.toSource.call([])'), true); +assertEq(raisesException(TypeError)('Number.prototype.toSource.call(undefined)'), true); +assertEq(raisesException(TypeError)('Number.prototype.toSource.call(new Boolean(true))'), true); + +assertEq(completesNormally('Number.prototype.toSource.call(42)'), true); +assertEq(completesNormally('Number.prototype.toSource.call(new Number(42))'), true); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/String-methods-infinite-recursion.js b/js/src/tests/ecma_5/extensions/String-methods-infinite-recursion.js new file mode 100644 index 000000000..a5972d8c3 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/String-methods-infinite-recursion.js @@ -0,0 +1,36 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 657585; +var summary = + 'Guard against infinite recursion when converting |this| to string for the ' + + 'String.prototype.* methods'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +try +{ + var obj = {}; + obj.toString = String.prototype.charAt; + "" + obj; + throw new Error("should have thrown"); +} +catch (e) +{ + assertEq(e instanceof InternalError, true, + "should have thrown InternalError for over-recursion, got: " + e); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/String-toSource.js b/js/src/tests/ecma_5/extensions/String-toSource.js new file mode 100644 index 000000000..0614e574c --- /dev/null +++ b/js/src/tests/ecma_5/extensions/String-toSource.js @@ -0,0 +1,14 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +assertEq(raisesException(TypeError)('String.prototype.toSource.call(42)'), true); +assertEq(raisesException(TypeError)('String.prototype.toSource.call(true)'), true); +assertEq(raisesException(TypeError)('String.prototype.toSource.call({})'), true); +assertEq(raisesException(TypeError)('String.prototype.toSource.call(null)'), true); +assertEq(raisesException(TypeError)('String.prototype.toSource.call([])'), true); +assertEq(raisesException(TypeError)('String.prototype.toSource.call(undefined)'), true); +assertEq(completesNormally('String.prototype.toSource.call("")'), true); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/__proto__.js b/js/src/tests/ecma_5/extensions/__proto__.js new file mode 100644 index 000000000..aa6d60876 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/__proto__.js @@ -0,0 +1,53 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = '__proto__.js'; +var BUGNUMBER = 770344; +var summary = "__proto__ as accessor"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var protoDesc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__"); +assertEq(protoDesc !== null, true); +assertEq(typeof protoDesc, "object"); +assertEq(protoDesc.hasOwnProperty("get"), true); +assertEq(protoDesc.hasOwnProperty("set"), true); +assertEq(protoDesc.hasOwnProperty("enumerable"), true); +assertEq(protoDesc.hasOwnProperty("configurable"), true); +assertEq(protoDesc.hasOwnProperty("value"), false); +assertEq(protoDesc.hasOwnProperty("writable"), false); + +assertEq(protoDesc.configurable, true); +assertEq(protoDesc.enumerable, false); +assertEq(typeof protoDesc.get, "function", protoDesc.get + ""); +assertEq(typeof protoDesc.set, "function", protoDesc.set + ""); + +assertEq(delete Object.prototype.__proto__, true); +assertEq(Object.getOwnPropertyDescriptor(Object.prototype, "__proto__"), + undefined); + +var obj = {}; +obj.__proto__ = 5; +assertEq(Object.getPrototypeOf(obj), Object.prototype); +assertEq(obj.hasOwnProperty("__proto__"), true); + +var desc = Object.getOwnPropertyDescriptor(obj, "__proto__"); +assertEq(desc !== null, true); +assertEq(typeof desc, "object"); +assertEq(desc.value, 5); +assertEq(desc.writable, true); +assertEq(desc.enumerable, true); +assertEq(desc.configurable, true); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/arguments-property-access-in-function.js b/js/src/tests/ecma_5/extensions/arguments-property-access-in-function.js new file mode 100644 index 000000000..f8c7e97f1 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/arguments-property-access-in-function.js @@ -0,0 +1,58 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden <jwalden+code@mit.edu> + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 721322; +var summary = + 'f.arguments must trigger an arguments object in non-strict mode functions'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var obj = + { + test: function() + { + var args = obj.test.arguments; + assertEq(args !== null, true); + assertEq(args[0], 5); + assertEq(args[1], undefined); + assertEq(args.length, 2); + } + }; +obj.test(5, undefined); + +var sobj = + { + test: function() + { + "use strict"; + + try + { + var args = sobj.test.arguments; + throw new Error("access to arguments property of strict mode " + + "function didn't throw"); + } + catch (e) + { + assertEq(e instanceof TypeError, true, + "should have thrown TypeError, instead got: " + e); + } + } + }; +sobj.test(5, undefined); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/array-inherited-__proto__.js b/js/src/tests/ecma_5/extensions/array-inherited-__proto__.js new file mode 100644 index 000000000..0409d4757 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/array-inherited-__proto__.js @@ -0,0 +1,32 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'array-inherited-__proto__.js'; +var BUGNUMBER = 769041; +var summary = + "The [[Prototype]] of an object whose prototype chain contains an array " + + "isn't that array's [[Prototype]]"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var arr = []; +assertEq(Array.isArray(arr), true); +var objWithArrPrototype = Object.create(arr); +assertEq(!Array.isArray(objWithArrPrototype), true); +assertEq(objWithArrPrototype.__proto__, arr); +var objWithArrGrandPrototype = Object.create(objWithArrPrototype); +assertEq(!Array.isArray(objWithArrGrandPrototype), true); +assertEq(objWithArrGrandPrototype.__proto__, objWithArrPrototype); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/array-pop-proxy.js b/js/src/tests/ecma_5/extensions/array-pop-proxy.js new file mode 100644 index 000000000..15c230977 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/array-pop-proxy.js @@ -0,0 +1,24 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'array-pop-proxy.js'; +var BUGNUMBER = 858381; +var summary = "Behavior of [].pop on proxies"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var p = new Proxy([0, 1, 2], {}); +Array.prototype.pop.call(p); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/array-toString-recursion.js b/js/src/tests/ecma_5/extensions/array-toString-recursion.js new file mode 100644 index 000000000..aa5d856c3 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/array-toString-recursion.js @@ -0,0 +1,46 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 635389; +var summary = 'Infinite recursion via [].{toString,toLocaleString,join}'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +try +{ + var x = []; + x.join = Array.prototype.toString; + "" + x; + throw new Error("should have thrown"); +} +catch (e) +{ + assertEq(e instanceof InternalError, true, + "should have thrown for over-recursion"); +} + +try +{ + var x = { toString: Array.prototype.toString, join: Array.prototype.toString }; + "" + x; + throw new Error("should have thrown"); +} +catch (e) +{ + assertEq(e instanceof InternalError, true, + "should have thrown for over-recursion"); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/browser.js b/js/src/tests/ecma_5/extensions/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_5/extensions/browser.js diff --git a/js/src/tests/ecma_5/extensions/bug472534.js b/js/src/tests/ecma_5/extensions/bug472534.js new file mode 100644 index 000000000..0c7d5f3ec --- /dev/null +++ b/js/src/tests/ecma_5/extensions/bug472534.js @@ -0,0 +1,30 @@ +function monthNames () { + return [ + /jan(uar(y)?)?/, 0, + /feb(ruar(y)?)?/, 1, + /m\u00e4r|mar|m\u00e4rz|maerz|march/, 2, + /apr(il)?/, 3, + /ma(i|y)/, 4, + /jun(i|o|e)?/, 5, + /jul(i|y)?/, 6, + /aug(ust)?/, 7, + /sep((t)?(ember))?/, 8, + /o(c|k)t(ober)?/, 9, + /nov(ember)?/, 10, + /de(c|z)(ember)?/, 11 + ]; +}; + +var actual = ''; +var expected = '(jan(uar(y)?)?)|(feb(ruar(y)?)?)|(m\\u00e4r|mar|m\\u00e4rz|maerz|march)|(apr(il)?)|(ma(i|y))|(jun(i|o|e)?)|(jul(i|y)?)|(aug(ust)?)|(sep((t)?(ember))?)|(o(c|k)t(ober)?)|(nov(ember)?)|(de(c|z)(ember)?)'; +var mn = monthNames(); +for (var i = 0; i < mn.length; ++i) { + if (actual) + actual += '|'; + actual += '(' + mn[i++].source + ')'; +} + +assertEq(actual, expected); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/bug496985.js b/js/src/tests/ecma_5/extensions/bug496985.js new file mode 100644 index 000000000..be1dd19cf --- /dev/null +++ b/js/src/tests/ecma_5/extensions/bug496985.js @@ -0,0 +1,12 @@ +var a = function() { + return function ({x: arguments}) { + return arguments; + } +} +var b = eval(uneval(a)); + +assertEq(a()({x: 1}), 1); +assertEq(b()({x: 1}), 1); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/bug566661.js b/js/src/tests/ecma_5/extensions/bug566661.js new file mode 100644 index 000000000..0e22d8dbd --- /dev/null +++ b/js/src/tests/ecma_5/extensions/bug566661.js @@ -0,0 +1,6 @@ +var f = function (q) { return q['\xC7']; } +var d = eval(uneval(f)); +assertEq(d({'\xC7': 'good'}), 'good'); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/builtin-function-arguments-caller.js b/js/src/tests/ecma_5/extensions/builtin-function-arguments-caller.js new file mode 100644 index 000000000..2acf5f452 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/builtin-function-arguments-caller.js @@ -0,0 +1,60 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'builtin-function-arguments-caller.js'; +var BUGNUMBER = 929642; +var summary = + "Built-in functions defined in ECMAScript pick up arguments/caller " + + "properties from Function.prototype"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function expectNoProperty(obj, prop) +{ + var desc = Object.getOwnPropertyDescriptor(obj, prop); + assertEq(desc, undefined, + "should be no '" + prop + "' property on " + obj); +} + +// Test a builtin that's native. +expectNoProperty(Object, "arguments"); +expectNoProperty(Object, "caller"); + +// Also test a builtin that's self-hosted. +expectNoProperty(Array.prototype.indexOf, "arguments"); +expectNoProperty(Array.prototype.indexOf, "caller"); + +// Test the Function construct for good measure, because it's so intricately +// invovled in bootstrapping. +expectNoProperty(Function, "arguments"); +expectNoProperty(Function, "caller"); + +var argsDesc = Object.getOwnPropertyDescriptor(Function.prototype, "arguments"); +var callerDesc = Object.getOwnPropertyDescriptor(Function.prototype, "caller"); + +var argsGet = argsDesc.get, argsSet = argsDesc.set; + +expectNoProperty(argsGet, "arguments"); +expectNoProperty(argsGet, "caller"); +expectNoProperty(argsSet, "arguments"); +expectNoProperty(argsSet, "caller"); + +var callerGet = callerDesc.get, callerSet = callerDesc.set; + +expectNoProperty(callerGet, "arguments"); +expectNoProperty(callerGet, "caller"); +expectNoProperty(callerSet, "arguments"); +expectNoProperty(callerSet, "caller"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/cross-global-eval-is-indirect.js b/js/src/tests/ecma_5/extensions/cross-global-eval-is-indirect.js new file mode 100644 index 000000000..6cd35846b --- /dev/null +++ b/js/src/tests/ecma_5/extensions/cross-global-eval-is-indirect.js @@ -0,0 +1,60 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs newGlobal() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 608473; +var summary = + '|var eval = otherWindow.eval; eval(...)| should behave like indirectly ' + + 'calling that eval from a script in that other window'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var originalEval = eval; +var res; + +function f() +{ + return [this, eval("this")]; +} + +var otherGlobalSameCompartment = newGlobal("same-compartment"); + +eval = otherGlobalSameCompartment.eval; +res = new f(); +assertEq(res[0] !== res[1], true); +assertEq(res[0] !== this, true); +assertEq(res[0] instanceof f, true); +assertEq(res[1], otherGlobalSameCompartment); + +res = f(); +assertEq(res[0] !== res[1], true); +assertEq(res[0], this); +assertEq(res[1], otherGlobalSameCompartment); + +var otherGlobalDifferentCompartment = newGlobal(); + +eval = otherGlobalDifferentCompartment.eval; +res = new f(); +assertEq(res[0] !== res[1], true); +assertEq(res[0] !== this, true); +assertEq(res[0] instanceof f, true); +assertEq(res[1], otherGlobalDifferentCompartment); + +res = f(); +assertEq(res[0] !== res[1], true); +assertEq(res[0], this); +assertEq(res[1], otherGlobalDifferentCompartment); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/cross-global-getPrototypeOf.js b/js/src/tests/ecma_5/extensions/cross-global-getPrototypeOf.js new file mode 100644 index 000000000..1480a8ea1 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/cross-global-getPrototypeOf.js @@ -0,0 +1,55 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs newGlobal() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 770344; +var summary = "Object.getPrototypeOf behavior across compartments"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var other = newGlobal(); + +var getProto = Object.getPrototypeOf; +var otherGetProto = other.Object.getPrototypeOf; + +var proto = {}; +var obj = Object.create(proto); +assertEq(getProto(obj), proto); +assertEq(otherGetProto(obj), proto); + +other.proto = proto; +var otherObj = other.evaluate("Object.create(proto)"); +assertEq(getProto(otherObj), proto); +assertEq(otherGetProto(otherObj), proto); + +var p = other.evaluate("({})"); +var objOtherProto = Object.create(p); +assertEq(getProto(objOtherProto), p); +assertEq(otherGetProto(objOtherProto), p); + +other.evaluate("var otherProto = { otherProto: 1 }; " + + "var otherObj = Object.create(otherProto);"); +assertEq(getProto(other.otherObj), other.otherProto); +assertEq(otherGetProto(other.otherObj), other.otherProto); + +other.evaluate("var newOtherProto = { newOtherProto: 1 }; " + + "otherObj.__proto__ = newOtherProto;"); +assertEq(otherGetProto(other.otherObj), other.newOtherProto); + +// TODO This assertion fails due to bug 764307 +//assertEq(getProto(other.otherObj), other.newOtherProto); + + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/destructuring-__proto__-shorthand-assignment-before-var.js b/js/src/tests/ecma_5/extensions/destructuring-__proto__-shorthand-assignment-before-var.js new file mode 100644 index 000000000..da0da55c8 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/destructuring-__proto__-shorthand-assignment-before-var.js @@ -0,0 +1,49 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'destructuring-__proto__-shorthand-assignment-before-var.js'; +var BUGNUMBER = 963641; +var summary = "{ __proto__ } should work as a destructuring assignment pattern"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function objectWithProtoProperty(v) +{ + var obj = {}; + return Object.defineProperty(obj, "__proto__", + { + enumerable: true, + configurable: true, + writable: true, + value: v + }); +} + +({ __proto__ } = objectWithProtoProperty(17)); +assertEq(__proto__, 17); + +var { __proto__ } = objectWithProtoProperty(42); +assertEq(__proto__, 42); + +function nested() +{ + ({ __proto__ } = objectWithProtoProperty(undefined)); + assertEq(__proto__, undefined); + + var { __proto__ } = objectWithProtoProperty("fnord"); + assertEq(__proto__, "fnord"); +} +nested(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/destructuring-__proto__-shorthand-assignment.js b/js/src/tests/ecma_5/extensions/destructuring-__proto__-shorthand-assignment.js new file mode 100644 index 000000000..0ab26465f --- /dev/null +++ b/js/src/tests/ecma_5/extensions/destructuring-__proto__-shorthand-assignment.js @@ -0,0 +1,49 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'destructuring-__proto__-shorthand-assignment.js'; +var BUGNUMBER = 963641; +var summary = "{ __proto__ } should work as a destructuring assignment pattern"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function objectWithProtoProperty(v) +{ + var obj = {}; + return Object.defineProperty(obj, "__proto__", + { + enumerable: true, + configurable: true, + writable: true, + value: v + }); +} + +var { __proto__ } = objectWithProtoProperty(42); +assertEq(__proto__, 42); + +({ __proto__ } = objectWithProtoProperty(17)); +assertEq(__proto__, 17); + +function nested() +{ + var { __proto__ } = objectWithProtoProperty("fnord"); + assertEq(__proto__, "fnord"); + + ({ __proto__ } = objectWithProtoProperty(undefined)); + assertEq(__proto__, undefined); +} +nested(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/destructuring-__proto__-target-assignment.js b/js/src/tests/ecma_5/extensions/destructuring-__proto__-target-assignment.js new file mode 100644 index 000000000..9e8ec7217 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/destructuring-__proto__-target-assignment.js @@ -0,0 +1,50 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'destructuring-__proto__-target--assignment.js'; +var BUGNUMBER = 963641; +var summary = + "{ __proto__: target } should work as a destructuring assignment pattern"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function objectWithProtoProperty(v) +{ + var obj = {}; + return Object.defineProperty(obj, "__proto__", + { + enumerable: true, + configurable: true, + writable: true, + value: v + }); +} + +var { __proto__: target } = objectWithProtoProperty(null); +assertEq(target, null); + +({ __proto__: target } = objectWithProtoProperty("aacchhorrt")); +assertEq(target, "aacchhorrt"); + +function nested() +{ + var { __proto__: target } = objectWithProtoProperty(3.141592654); + assertEq(target, 3.141592654); + + ({ __proto__: target } = objectWithProtoProperty(-0)); + assertEq(target, -0); +} +nested(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/destructuring-for-inof-__proto__.js b/js/src/tests/ecma_5/extensions/destructuring-for-inof-__proto__.js new file mode 100644 index 000000000..283dee314 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/destructuring-for-inof-__proto__.js @@ -0,0 +1,85 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'destructuring-for-inof-__proto__.js'; +var BUGNUMBER = 963641; +var summary = + "__proto__ should work in destructuring patterns as the targets of " + + "for-in/for-of loops"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function objectWithProtoProperty(v) +{ + var obj = {}; + return Object.defineProperty(obj, "__proto__", + { + enumerable: true, + configurable: true, + writable: true, + value: v + }); +} + +function* objectWithProtoGenerator(v) +{ + yield objectWithProtoProperty(v); +} + +function* identityGenerator(v) +{ + yield v; +} + +for (var { __proto__: target } of objectWithProtoGenerator(null)) + assertEq(target, null); + +for ({ __proto__: target } of objectWithProtoGenerator("aacchhorrt")) + assertEq(target, "aacchhorrt"); + +for ({ __proto__: target } of identityGenerator(42)) + assertEq(target, Number.prototype); + +for (var { __proto__: target } in { prop: "kneedle" }) + assertEq(target, String.prototype); + +for ({ __proto__: target } in { prop: "snork" }) + assertEq(target, String.prototype); + +for ({ __proto__: target } in { prop: "ohia" }) + assertEq(target, String.prototype); + +function nested() +{ + for (var { __proto__: target } of objectWithProtoGenerator(null)) + assertEq(target, null); + + for ({ __proto__: target } of objectWithProtoGenerator("aacchhorrt")) + assertEq(target, "aacchhorrt"); + + for ({ __proto__: target } of identityGenerator(42)) + assertEq(target, Number.prototype); + + for (var { __proto__: target } in { prop: "kneedle" }) + assertEq(target, String.prototype); + + for ({ __proto__: target } in { prop: "snork" }) + assertEq(target, String.prototype); + + for ({ __proto__: target } in { prop: "ohia" }) + assertEq(target, String.prototype); +} +nested(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/error-tostring-function.js b/js/src/tests/ecma_5/extensions/error-tostring-function.js new file mode 100644 index 000000000..5e92f1075 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/error-tostring-function.js @@ -0,0 +1,45 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 894653; +var summary = + "Error.prototype.toString called on function objects should work as on any " + + "object"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function ErrorToString(v) +{ + return Error.prototype.toString.call(v); +} + +// The name property of function objects isn't standardized, so this must be an +// extension-land test. + +assertEq(ErrorToString(function f(){}), "f"); +assertEq(ErrorToString(function g(){}), "g"); +assertEq(ErrorToString(function(){}), ""); + +var fn1 = function() {}; +fn1.message = "ohai"; +assertEq(ErrorToString(fn1), "ohai"); + +var fn2 = function blerch() {}; +fn2.message = "fnord"; +assertEq(ErrorToString(fn2), "blerch: fnord"); + +var fn3 = function() {}; +fn3.message = ""; +assertEq(ErrorToString(fn3), ""); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete!"); diff --git a/js/src/tests/ecma_5/extensions/es5ish-defineGetter-defineSetter.js b/js/src/tests/ecma_5/extensions/es5ish-defineGetter-defineSetter.js new file mode 100644 index 000000000..681a157a8 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/es5ish-defineGetter-defineSetter.js @@ -0,0 +1,281 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 715821; +var summary = "Implement __define[GS]etter__ using Object.defineProperty"; + +print(BUGNUMBER + ": " + summary); + +/************* + * UTILITIES * + *************/ + +function s(desc) +{ + if (typeof desc === "undefined") + return "<undefined>"; + assertEq(typeof desc, "object"); + assertEq(desc !== null, true); + + var str = "<enumerable: <" + desc.enumerable + ">, " + + " configurable: <" + desc.configurable + ">,"; + + if (desc.hasOwnProperty("value")) + { + return str + + " value: <" + desc.value + ">," + + " writable: <" + desc.writable + ">>"; + } + + return str + + " get: <" + desc.get + ">," + + " set: <" + desc.set + ">>"; +} + +function checkField(field, desc, expected) +{ + var present = desc.hasOwnProperty(field); + assertEq(present, expected.hasOwnProperty(field), + field + " presence mismatch (got " + s(desc) + ", expected " + s(expected) + ")"); + if (present) + { + assertEq(desc[field], expected[field], + field + " value mismatch (got " + s(desc) + ", expected " + s(expected) + ")"); + } +} + +function check(obj, prop, expected) +{ + var desc = Object.getOwnPropertyDescriptor(obj, prop); + assertEq(typeof desc, typeof expected, + "type mismatch (got " + s(desc) + ", expected " + s(expected) + ")"); + + assertEq(desc.hasOwnProperty("get"), desc.hasOwnProperty("set"), + "bad descriptor: " + s(desc)); + assertEq(desc.hasOwnProperty("value"), desc.hasOwnProperty("writable"), + "bad descriptor: " + s(desc)); + + assertEq(desc.hasOwnProperty("get"), !desc.hasOwnProperty("value"), + "bad descriptor: " + s(desc)); + + checkField("get", desc, expected); + checkField("set", desc, expected); + checkField("value", desc, expected); + checkField("writable", desc, expected); + checkField("enumerable", desc, expected); + checkField("configurable", desc, expected); +} + +function expectTypeError(f) +{ + try + { + f(); + throw new Error("no error thrown"); + } + catch (e) + { + assertEq(e instanceof TypeError, true, + "wrong error thrown: got " + e + ", not a TypeError"); + } +} + +/************** + * BEGIN TEST * + **************/ + +// Adding a new getter, overwriting an existing one + +function g1() { } +var gobj = {}; +gobj.__defineGetter__("foo", g1); +check(gobj, "foo", { get: g1, set: undefined, enumerable: true, configurable: true }); + +function g2() { } +gobj.__defineGetter__("foo", g2); +check(gobj, "foo", { get: g2, set: undefined, enumerable: true, configurable: true }); + +/******************************************************************************/ + +// Adding a new setter, overwriting an existing one + +function s1() { } +var sobj = {}; +sobj.__defineSetter__("bar", s1); +check(sobj, "bar", { get: undefined, set: s1, enumerable: true, configurable: true }); + +function s2() { } +sobj.__defineSetter__("bar", s2); +check(sobj, "bar", { get: undefined, set: s2, enumerable: true, configurable: true }); + +/******************************************************************************/ + +// Adding a new getter, then adding a setter +// Changing an existing accessor's enumerability, then "null"-changing the accessor +// Changing an accessor's configurability, then "null"-changing and real-changing the accessor + +function g3() { } +var gsobj = {}; +gsobj.__defineGetter__("baz", g3); +check(gsobj, "baz", { get: g3, set: undefined, enumerable: true, configurable: true }); + +function s3() { } +gsobj.__defineSetter__("baz", s3); +check(gsobj, "baz", { get: g3, set: s3, enumerable: true, configurable: true }); + +Object.defineProperty(gsobj, "baz", { enumerable: false }); +check(gsobj, "baz", { get: g3, set: s3, enumerable: false, configurable: true }); + +gsobj.__defineGetter__("baz", g3); +check(gsobj, "baz", { get: g3, set: s3, enumerable: true, configurable: true }); + +Object.defineProperty(gsobj, "baz", { enumerable: false }); +check(gsobj, "baz", { get: g3, set: s3, enumerable: false, configurable: true }); + +gsobj.__defineSetter__("baz", s3); +check(gsobj, "baz", { get: g3, set: s3, enumerable: true, configurable: true }); + +Object.defineProperty(gsobj, "baz", { configurable: false }); +expectTypeError(function() { gsobj.__defineSetter__("baz", s2); }); +expectTypeError(function() { gsobj.__defineSetter__("baz", s3); }); +check(gsobj, "baz", { get: g3, set: s3, enumerable: true, configurable: false }); + +/******************************************************************************/ + +// Adding a new setter, then adding a getter +// Changing an existing accessor's enumerability, then "null"-changing the accessor +// Changing an accessor's configurability, then "null"-changing and real-changing the accessor + +function s4() { } +var sgobj = {}; +sgobj.__defineSetter__("baz", s4); +check(sgobj, "baz", { get: undefined, set: s4, enumerable: true, configurable: true }); + +function g4() { } +sgobj.__defineGetter__("baz", g4); +check(sgobj, "baz", { get: g4, set: s4, enumerable: true, configurable: true }); + +Object.defineProperty(sgobj, "baz", { enumerable: false }); +check(sgobj, "baz", { get: g4, set: s4, enumerable: false, configurable: true }); + +sgobj.__defineSetter__("baz", s4); +check(sgobj, "baz", { get: g4, set: s4, enumerable: true, configurable: true }); + +Object.defineProperty(sgobj, "baz", { enumerable: false }); +check(sgobj, "baz", { get: g4, set: s4, enumerable: false, configurable: true }); + +sgobj.__defineSetter__("baz", s4); +check(sgobj, "baz", { get: g4, set: s4, enumerable: true, configurable: true }); + +Object.defineProperty(sgobj, "baz", { configurable: false }); +expectTypeError(function() { sgobj.__defineGetter__("baz", g3); }); +expectTypeError(function() { sgobj.__defineSetter__("baz", s4); }); +check(sgobj, "baz", { get: g4, set: s4, enumerable: true, configurable: false }); + +/******************************************************************************/ + +// Adding a getter over a writable data property + +function g5() { } +var gover = { quux: 17 }; +check(gover, "quux", { value: 17, writable: true, enumerable: true, configurable: true }); + +gover.__defineGetter__("quux", g5); +check(gover, "quux", { get: g5, set: undefined, enumerable: true, configurable: true }); + +/******************************************************************************/ + +// Adding a setter over a writable data property + +function s5() { } +var sover = { quux: 17 }; +check(sover, "quux", { value: 17, writable: true, enumerable: true, configurable: true }); + +sover.__defineSetter__("quux", s5); +check(sover, "quux", { get: undefined, set: s5, enumerable: true, configurable: true }); + +/******************************************************************************/ + +// Adding a getter over a non-writable data property + +function g6() { } +var gnover = { eit: 17 }; +check(gnover, "eit", { value: 17, writable: true, enumerable: true, configurable: true }); +Object.defineProperty(gnover, "eit", { writable: false }); +check(gnover, "eit", { value: 17, writable: false, enumerable: true, configurable: true }); + +gnover.__defineGetter__("eit", g6); +check(gnover, "eit", { get: g6, set: undefined, enumerable: true, configurable: true }); + +/******************************************************************************/ + +// Adding a setter over a non-writable data property + +function s6() { } +var snover = { eit: 17 }; +check(snover, "eit", { value: 17, writable: true, enumerable: true, configurable: true }); +Object.defineProperty(snover, "eit", { writable: false }); +check(snover, "eit", { value: 17, writable: false, enumerable: true, configurable: true }); + +snover.__defineSetter__("eit", s6); +check(snover, "eit", { get: undefined, set: s6, enumerable: true, configurable: true }); + +/******************************************************************************/ + +// Adding a getter over a non-configurable, writable data property + +function g7() { } +var gncover = { moo: 17 }; +check(gncover, "moo", { value: 17, writable: true, enumerable: true, configurable: true }); +Object.defineProperty(gncover, "moo", { configurable: false }); +check(gncover, "moo", { value: 17, writable: true, enumerable: true, configurable: false }); + +expectTypeError(function() { gncover.__defineGetter__("moo", g7); }); +check(gncover, "moo", { value: 17, writable: true, enumerable: true, configurable: false }); + +/******************************************************************************/ + +// Adding a setter over a non-configurable, writable data property + +function s7() { } +var sncover = { moo: 17 }; +check(sncover, "moo", { value: 17, writable: true, enumerable: true, configurable: true }); +Object.defineProperty(sncover, "moo", { configurable: false }); +check(sncover, "moo", { value: 17, writable: true, enumerable: true, configurable: false }); + +expectTypeError(function() { sncover.__defineSetter__("moo", s7); }); +check(sncover, "moo", { value: 17, writable: true, enumerable: true, configurable: false }); + +/******************************************************************************/ + +// Adding a getter over a non-configurable, non-writable data property + +function g8() { } +var gncwover = { fwoosh: 17 }; +check(gncwover, "fwoosh", { value: 17, writable: true, enumerable: true, configurable: true }); +Object.defineProperty(gncwover, "fwoosh", { writable: false, configurable: false }); +check(gncwover, "fwoosh", { value: 17, writable: false, enumerable: true, configurable: false }); + +expectTypeError(function() { gncwover.__defineGetter__("fwoosh", g7); }); +check(gncwover, "fwoosh", { value: 17, writable: false, enumerable: true, configurable: false }); + +/******************************************************************************/ + +// Adding a setter over a non-configurable, non-writable data property + +function s8() { } +var sncwover = { fwoosh: 17 }; +check(sncwover, "fwoosh", { value: 17, writable: true, enumerable: true, configurable: true }); +Object.defineProperty(sncwover, "fwoosh", { writable: false, configurable: false }); +check(sncwover, "fwoosh", { value: 17, writable: false, enumerable: true, configurable: false }); + +expectTypeError(function() { sncwover.__defineSetter__("fwoosh", s7); }); +check(sncwover, "fwoosh", { value: 17, writable: false, enumerable: true, configurable: false }); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/eval-native-callback-is-indirect.js b/js/src/tests/ecma_5/extensions/eval-native-callback-is-indirect.js new file mode 100644 index 000000000..662f619ee --- /dev/null +++ b/js/src/tests/ecma_5/extensions/eval-native-callback-is-indirect.js @@ -0,0 +1,43 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 604504; +var summary = "eval called from a native function is indirect"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var originalEval = eval; + +var global = this; +var directCheckCode = "this === global"; + +function testArrayGeneric() +{ + var global = "psych!"; + var eval = Array.map; + + var mapped = eval([directCheckCode], originalEval); + assertEq(mapped[0], true); +} + +function testStringGeneric() +{ + var global = "psych!"; + var eval = String.replace; + + var newString = eval(directCheckCode, directCheckCode, originalEval); + assertEq(newString, "true"); +} +testStringGeneric(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/extension-methods-reject-null-undefined-this.js b/js/src/tests/ecma_5/extensions/extension-methods-reject-null-undefined-this.js new file mode 100644 index 000000000..5ea399fe8 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/extension-methods-reject-null-undefined-this.js @@ -0,0 +1,112 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 619283; +var summary = + "ECMAScript built-in methods that immediately throw when |this| is " + + "|undefined| or |null| (due to CheckObjectCoercible, ToObject, or ToString)"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// This test fills out for the non-standard methods which +// ecma_5/misc/builtin-methods-reject-null-undefined-this.js declines to test. + +var ClassToMethodMap = + { + Object: [/* + * Don't box this just yet for these methods -- they're used too + * much without qualification to do that. :-( + */ + /* "__defineGetter__", "__defineSetter__", */ + "__lookupGetter__", "__lookupSetter__", "watch", "unwatch", + "toSource"], + Function: ["toSource"], + Array: ["toSource"], + String: ["toSource", "quote", "bold", "italics", "fixed", "fontsize", + "fontcolor", "link", "anchor", "strike", "small", "big", "blink", + "sup", "sub", "substr", "trimLeft", "trimRight", "toJSON"], + Boolean: ["toSource", "toJSON"], + Number: ["toSource", "toJSON"], + Date: ["toSource", "toLocaleFormat", "getYear", "setYear", + "toGMTString"], + RegExp: ["toSource"], + Error: ["toSource"], + }; + +var badThisValues = [null, undefined]; + +function testMethod(Class, className, method) +{ + var expr; + + // Try out explicit this values + for (var i = 0, sz = badThisValues.length; i < sz; i++) + { + var badThis = badThisValues[i]; + + expr = className + ".prototype." + method + ".call(" + badThis + ")"; + try + { + Class.prototype[method].call(badThis); + throw new Error(expr + " didn't throw a TypeError"); + } + catch (e) + { + assertEq(e instanceof TypeError, true, + "wrong error for " + expr + ", instead threw " + e); + } + + expr = className + ".prototype." + method + ".apply(" + badThis + ")"; + try + { + Class.prototype[method].apply(badThis); + throw new Error(expr + " didn't throw a TypeError"); + } + catch (e) + { + assertEq(e instanceof TypeError, true, + "wrong error for " + expr + ", instead threw " + e); + } + } + + // ..and for good measure.. + + expr = "(0, " + className + ".prototype." + method + ")()" + try + { + // comma operator to call GetValue() on the method and de-Reference it + (0, Class.prototype[method])(); + throw new Error(expr + " didn't throw a TypeError"); + } + catch (e) + { + assertEq(e instanceof TypeError, true, + "wrong error for " + expr + ", instead threw " + e); + } +} + +for (var className in ClassToMethodMap) +{ + var Class = this[className]; + + var methodNames = ClassToMethodMap[className]; + for (var i = 0, sz = methodNames.length; i < sz; i++) + { + var method = methodNames[i]; + testMethod(Class, className, method); + } +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/function-caller-skips-eval-frames.js b/js/src/tests/ecma_5/extensions/function-caller-skips-eval-frames.js new file mode 100644 index 000000000..77eb99108 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/function-caller-skips-eval-frames.js @@ -0,0 +1,34 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +function innermost() { return arguments.callee.caller; } +function nest() { return eval("innermost();"); } +function nest2() { return nest(); } + +assertEq(nest2(), nest); + +var innermost = function innermost() { return arguments.callee.caller.caller; }; + +assertEq(nest2(), nest2); + +function nestTwice() { return eval("eval('innermost();');"); } +var nest = nestTwice; + +assertEq(nest2(), nest2); + +function innermostEval() { return eval("arguments.callee.caller"); } +var innermost = innermostEval; + +assertEq(nest2(), nestTwice); + +function innermostEvalTwice() { return eval('eval("arguments.callee.caller");'); } +var innermost = innermostEvalTwice; + +assertEq(nest2(), nestTwice); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/function-caller-strict-cross-global.js b/js/src/tests/ecma_5/extensions/function-caller-strict-cross-global.js new file mode 100644 index 000000000..45fd7b1b3 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/function-caller-strict-cross-global.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs newGlobal() +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +var g1 = newGlobal(); +g1.evaluate("function f() { return f.caller; }"); + +var g2 = newGlobal(); +g2.f = g1.f; + +try +{ + g2.evaluate("function g() { 'use strict'; return f(); } g()"); + throw new Error("failed to throw"); +} +catch (e) +{ + assertEq(e.constructor.name, "TypeError", + "expected TypeError accessing strict .caller across globals, got " + + e); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/function-definition-with.js b/js/src/tests/ecma_5/extensions/function-definition-with.js new file mode 100644 index 000000000..2277ad45f --- /dev/null +++ b/js/src/tests/ecma_5/extensions/function-definition-with.js @@ -0,0 +1,56 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs evaluate() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 577325; +var summary = 'Implement the ES5 algorithm for processing function statements'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var called, obj; + +function inFile1() { return "in file"; } +called = false; +obj = { set inFile1(v) { called = true; } }; +with (obj) { + function inFile1() { return "in file in with"; }; +} +assertEq(inFile1(), "in file in with"); +assertEq("set" in Object.getOwnPropertyDescriptor(obj, "inFile1"), true); +assertEq(called, false); + +evaluate("function notInFile1() { return 'not in file'; }"); +called = false; +obj = { set notInFile1(v) { called = true; return "not in file 2"; } }; +with (obj) { + function notInFile1() { return "not in file in with"; }; +} +assertEq(notInFile1(), "not in file in with"); +assertEq("set" in Object.getOwnPropertyDescriptor(obj, "notInFile1"), true); +assertEq(called, false); + +function inFile2() { return "in file 1"; } +called = false; +obj = + Object.defineProperty({}, "inFile2", + { value: 42, configurable: false, enumerable: false }); +with (obj) { + function inFile2() { return "in file 2"; }; +} +assertEq(inFile2(), "in file 2"); +assertEq(obj.inFile2, 42); + + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/function-properties.js b/js/src/tests/ecma_5/extensions/function-properties.js new file mode 100644 index 000000000..9585322ef --- /dev/null +++ b/js/src/tests/ecma_5/extensions/function-properties.js @@ -0,0 +1,21 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +function foo() +{ + assertEq(foo.arguments.length, 0); + assertEq(foo.caller, null); +} + +assertEq(foo.arguments, null); +assertEq(foo.caller, null); +foo(); +assertEq(foo.arguments, null); +assertEq(foo.caller, null); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/getOwnPropertyNames-__proto__.js b/js/src/tests/ecma_5/extensions/getOwnPropertyNames-__proto__.js new file mode 100644 index 000000000..91ee2d203 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/getOwnPropertyNames-__proto__.js @@ -0,0 +1,26 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 837630; +var summary ='__proto__ should show up with O.getOwnPropertyNames(O.prototype)'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var keys = Object.getOwnPropertyNames(Object.prototype); +assertEq(keys.indexOf("__proto__") >= 0, true, + "should have gotten __proto__ as a property of Object.prototype " + + "(got these properties: " + keys + ")"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/inc-dec-functioncall.js b/js/src/tests/ecma_5/extensions/inc-dec-functioncall.js new file mode 100644 index 000000000..b4de03c6c --- /dev/null +++ b/js/src/tests/ecma_5/extensions/inc-dec-functioncall.js @@ -0,0 +1,90 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 609756; +var summary = + "Perform ToNumber on the result of the |fun()| in |fun()++| before " + + "throwing"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var hadSideEffect; + +function f() +{ + return { valueOf: function() { hadSideEffect = true; return 0; } }; +} + +hadSideEffect = false; +assertThrowsInstanceOf(function() { f()++; }, ReferenceError); +assertEq(hadSideEffect, true); + +hadSideEffect = false; +assertThrowsInstanceOf(function() { + for (var i = 0; i < 20; i++) + { + if (i > 18) + f()++; + } +}, ReferenceError); +assertEq(hadSideEffect, true); + + +hadSideEffect = false; +assertThrowsInstanceOf(function() { f()--; }, ReferenceError); +assertEq(hadSideEffect, true); + +hadSideEffect = false; +assertThrowsInstanceOf(function() { + for (var i = 0; i < 20; i++) + { + if (i > 18) + f()--; + } +}, ReferenceError); +assertEq(hadSideEffect, true); + + +hadSideEffect = false; +assertThrowsInstanceOf(function() { ++f(); }, ReferenceError); +assertEq(hadSideEffect, true); + +hadSideEffect = false; +assertThrowsInstanceOf(function() { + for (var i = 0; i < 20; i++) + { + if (i > 18) + ++f(); + } +}, ReferenceError); +assertEq(hadSideEffect, true); + + +hadSideEffect = false; +assertThrowsInstanceOf(function() { --f(); }, ReferenceError); +assertEq(hadSideEffect, true); + +hadSideEffect = false; +assertThrowsInstanceOf(function() { + for (var i = 0; i < 20; i++) + { + if (i > 18) + --f(); + } +}, ReferenceError); +assertEq(hadSideEffect, true); + + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/iterator-in-catch.js b/js/src/tests/ecma_5/extensions/iterator-in-catch.js new file mode 100644 index 000000000..390b585e9 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/iterator-in-catch.js @@ -0,0 +1,20 @@ +//Bug 350712 + +function iterator () { + for (var i in []); +} + +try { + try { + throw 5; + } + catch(error if iterator()) { + assertEq(false, true); + } +} +catch(error) { + assertEq(error, 5); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/misplaced-inconsistent-directive.js b/js/src/tests/ecma_5/extensions/misplaced-inconsistent-directive.js new file mode 100644 index 000000000..b7b33001c --- /dev/null +++ b/js/src/tests/ecma_5/extensions/misplaced-inconsistent-directive.js @@ -0,0 +1,74 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs evaluate() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden <jwalden+code@mit.edu> + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1046964; +var summary = + "Misplaced directives (e.g. 'use strict') should trigger warnings if they " + + "contradict the actually-used semantics"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +options("strict"); +options("werror"); + +function evaluateNoRval(code) +{ + evaluate(code, { isRunOnce: true, noScriptRval: true }); +} + +function expectSyntaxError(code) +{ + try + { + evaluateNoRval(code); + throw new Error("didn't throw"); + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "should have thrown a SyntaxError, instead got:\n" + + " " + e + "\n" + + "when evaluating:\n" + + " " + code); + } +} + +expectSyntaxError("function f1() {} 'use strict'; function f2() {}"); +expectSyntaxError("function f3() { var x; 'use strict'; }"); + +if (isAsmJSCompilationAvailable()) + expectSyntaxError("function f4() {} 'use asm'; function f5() {}"); +expectSyntaxError("function f6() { var x; 'use strict'; }"); +if (isAsmJSCompilationAvailable()) + expectSyntaxError("'use asm'; function f7() {}"); + +// No errors expected -- useless non-directives, but not contrary to used +// semantics. +evaluateNoRval("'use strict'; function f8() {} 'use strict'; function f9() {}"); +evaluateNoRval("'use strict'; function f10() { var z; 'use strict' }"); + +if (isAsmJSCompilationAvailable()) { + try { + evaluateNoRval("function f11() { 'use asm'; return {}; }"); + } catch(e) { + if (!e.toString().includes("Successfully compiled asm.js code")) + throw e; + } +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/nested-delete-name-in-evalcode.js b/js/src/tests/ecma_5/extensions/nested-delete-name-in-evalcode.js new file mode 100644 index 000000000..7dfab0458 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/nested-delete-name-in-evalcode.js @@ -0,0 +1,85 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 616294; +var summary = + "|delete x| inside a function in eval code, where that eval code includes " + + "|var x| at top level, actually does delete the binding for x"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var f; + +function testOuterLet() +{ + return eval("let x; (function() { return delete x; })"); +} + +f = testOuterLet(); + +assertEq(f(), false); // can't delete lexical declarations => false + + +function testOuterForLet() +{ + return eval("for (let x; false; ); (function() { return delete x; })"); +} + +f = testOuterForLet(); + +assertEq(f(), true); // not there => true (only non-configurable => false) + + +function testOuterForInLet() +{ + return eval("for (let x in {}); (function() { return delete x; })"); +} + +f = testOuterForInLet(); + +assertEq(f(), true); // configurable, so remove => true +assertEq(f(), true); // not there => true (only non-configurable => false) + + +function testOuterNestedVarInForLet() +{ + return eval("for (let q = 0; q < 5; q++) { var x; } (function() { return delete x; })"); +} + +f = testOuterNestedVarInForLet(); + +assertEq(f(), true); // configurable, so remove => true +assertEq(f(), true); // there => true + + +function testArgumentShadowLet() +{ + return eval("let x; (function(x) { return delete x; })"); +} + +f = testArgumentShadowLet(); + +assertEq(f(), false); // non-configurable argument => false + + +function testFunctionLocal() +{ + return eval("(function() { let x; return delete x; })"); +} + +f = testFunctionLocal(); + +assertEq(f(), false); // defined by function code => not configurable => false + + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/preventExtensions-cross-global.js b/js/src/tests/ecma_5/extensions/preventExtensions-cross-global.js new file mode 100644 index 000000000..0cc68e0fb --- /dev/null +++ b/js/src/tests/ecma_5/extensions/preventExtensions-cross-global.js @@ -0,0 +1,49 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs newGlobal() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden <jwalden+code@mit.edu> + */ + +var gTestfile = 'preventExtensions-cross-global.js'; +//----------------------------------------------------------------------------- +var BUGNUMBER = 789897; +var summary = + "Object.preventExtensions and Object.isExtensible should work correctly " + + "across globals"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var otherGlobal = newGlobal(); + +var obj = {}; +assertEq(otherGlobal.Object.isExtensible(obj), true); +assertEq(otherGlobal.Object.preventExtensions(obj), obj); +assertEq(otherGlobal.Object.isExtensible(obj), false); + +var objFromOther = otherGlobal.Object(); +assertEq(Object.isExtensible(objFromOther), true); +assertEq(Object.preventExtensions(objFromOther), objFromOther); +assertEq(Object.isExtensible(objFromOther), false); + +var proxy = new Proxy({}, {}); +assertEq(otherGlobal.Object.isExtensible(proxy), true); +assertEq(otherGlobal.Object.preventExtensions(proxy), proxy); +assertEq(otherGlobal.Object.isExtensible(proxy), false); + +var proxyFromOther = otherGlobal.evaluate("new Proxy({}, {})"); +assertEq(Object.isExtensible(proxyFromOther), true); +assertEq(Object.preventExtensions(proxyFromOther), proxyFromOther); +assertEq(Object.isExtensible(proxyFromOther), false); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/proxy-array-target-length-definition.js b/js/src/tests/ecma_5/extensions/proxy-array-target-length-definition.js new file mode 100644 index 000000000..c573c4ba0 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/proxy-array-target-length-definition.js @@ -0,0 +1,55 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'proxy-array-target-length-definition.js'; +var BUGNUMBER = 905947; +var summary = + "Redefining an array's |length| property when redefining the |length| " + + "property on a proxy with an array as target"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var arr = []; +var p = new Proxy(arr, {}); + +function assertThrowsTypeError(f) +{ + try { + f(); + assertEq(false, true, "Must have thrown"); + } catch (e) { + assertEq(e instanceof TypeError, true, "Must have thrown TypeError"); + } +} + +// Redefining non-configurable length should throw a TypeError +assertThrowsTypeError(function () { Object.defineProperty(p, "length", { value: 17, configurable: true }); }); + +// Same here. +assertThrowsTypeError(function () { Object.defineProperty(p, "length", { value: 42, enumerable: true }); }); + +// Check the property went unchanged. +var pd = Object.getOwnPropertyDescriptor(p, "length"); +assertEq(pd.value, 0); +assertEq(pd.writable, true); +assertEq(pd.enumerable, false); +assertEq(pd.configurable, false); + +var ad = Object.getOwnPropertyDescriptor(arr, "length"); +assertEq(ad.value, 0); +assertEq(ad.writable, true); +assertEq(ad.enumerable, false); +assertEq(ad.configurable, false); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/proxy-enumeration.js b/js/src/tests/ecma_5/extensions/proxy-enumeration.js new file mode 100644 index 000000000..f872d635d --- /dev/null +++ b/js/src/tests/ecma_5/extensions/proxy-enumeration.js @@ -0,0 +1,4 @@ +var list = Object.getOwnPropertyNames(this); +var found = list.indexOf("Proxy") != -1; +assertEq(found, true) +reportCompare(true, true) diff --git a/js/src/tests/ecma_5/extensions/proxy-strict.js b/js/src/tests/ecma_5/extensions/proxy-strict.js new file mode 100644 index 000000000..9dc969685 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/proxy-strict.js @@ -0,0 +1,12 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var s = "grape"; +function f() { "use strict"; return this; } +var p = new Proxy(f, {}); +String.prototype.p = p; +assertEq(s.p(), "grape"); + +reportCompare(true,true); diff --git a/js/src/tests/ecma_5/extensions/regress-bug567606.js b/js/src/tests/ecma_5/extensions/regress-bug567606.js new file mode 100644 index 000000000..6bebc8063 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/regress-bug567606.js @@ -0,0 +1,19 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +var global = this; + +(function() { + function f() { + this.b = function() {}; + Object.defineProperty(this, "b", ({ + configurable: global.__defineSetter__("", function() {}) + })); + } + for (y of [0]) { + _ = new f(); + } +})(); +uneval(this); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/regress-bug607284.js b/js/src/tests/ecma_5/extensions/regress-bug607284.js new file mode 100644 index 000000000..7d2c4921d --- /dev/null +++ b/js/src/tests/ecma_5/extensions/regress-bug607284.js @@ -0,0 +1,16 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +if ("evalcx" in this) { + var sandbox = evalcx(""); + var obj = { get foo() { throw("FAIL"); } }; + var getter = obj.__lookupGetter__("foo"); + var desc = sandbox.Object.getOwnPropertyDescriptor(obj, "foo"); + reportCompare(desc.get, getter, "getter is correct"); + reportCompare(desc.set, undefined, "setter is correct"); +} +else { + reportCompare(true, true); +} diff --git a/js/src/tests/ecma_5/extensions/regress-bug629723.js b/js/src/tests/ecma_5/extensions/regress-bug629723.js new file mode 100644 index 000000000..6c826e0c2 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/regress-bug629723.js @@ -0,0 +1,16 @@ +function f(foo) { + "use strict"; + foo.bar; +} + +var actual; +try { + f(); + actual = "no error"; +} catch (x) { + actual = (x instanceof TypeError) ? "type error" : "some other error"; + actual += (/use strict/.test(x)) ? " with directive" : " without directive"; +} + +reportCompare("type error without directive", actual, + "decompiled expressions in error messages should not include directive prologues"); diff --git a/js/src/tests/ecma_5/extensions/reviver-mutates-holder-array-ccw.js b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-array-ccw.js new file mode 100644 index 000000000..e51e19903 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-array-ccw.js @@ -0,0 +1,39 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden <jwalden+code@mit.edu> + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 901351; +var summary = "Behavior when the JSON.parse reviver mutates the holder array"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var proxyObj = null; + +var arr = JSON.parse('[0, 1]', function(prop, v) { + if (prop === "0") + { + proxyObj = newGlobal().evaluate("({ c: 17, d: 42 })"); + this[1] = proxyObj; + } + return v; +}); + +assertEq(arr[0], 0); +assertEq(arr[1], proxyObj); +assertEq(arr[1].c, 17); +assertEq(arr[1].d, 42); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/reviver-mutates-holder-array-nonnative.js b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-array-nonnative.js new file mode 100644 index 000000000..de4ad7032 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-array-nonnative.js @@ -0,0 +1,46 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden <jwalden+code@mit.edu> + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 901380; +var summary = "Behavior when JSON.parse walks over a non-native object"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var typedArray = null; + +var observedTypedArrayElementCount = 0; + +var arr = JSON.parse('[0, 1]', function(prop, v) { + if (prop === "0" && Array.isArray(this)) // exclude typedArray[0] + { + typedArray = new Int8Array(1); + this[1] = typedArray; + } + if (this instanceof Int8Array) + { + assertEq(prop, "0"); + observedTypedArrayElementCount++; + } + return v; +}); + +assertEq(arr[0], 0); +assertEq(arr[1], typedArray); + +assertEq(observedTypedArrayElementCount, 1); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/reviver-mutates-holder-array.js b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-array.js new file mode 100644 index 000000000..f4f89ac0a --- /dev/null +++ b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-array.js @@ -0,0 +1,39 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden <jwalden+code@mit.edu> + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 901351; +var summary = "Behavior when the JSON.parse reviver mutates the holder array"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var proxyObj = null; + +var arr = JSON.parse('[0, 1]', function(prop, v) { + if (prop === "0") + { + proxyObj = new Proxy({ c: 17, d: 42 }, {}); + this[1] = proxyObj; + } + return v; +}); + +assertEq(arr[0], 0); +assertEq(arr[1], proxyObj); +assertEq(arr[1].c, 17); +assertEq(arr[1].d, 42); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/reviver-mutates-holder-object-ccw.js b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-object-ccw.js new file mode 100644 index 000000000..546a57e91 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-object-ccw.js @@ -0,0 +1,56 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden <jwalden+code@mit.edu> + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 901351; +var summary = "Behavior when the JSON.parse reviver mutates the holder object"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// A little trickiness to account for the undefined-ness of property +// enumeration order. +var first = "unset"; + +var proxyObj = null; + +var obj = JSON.parse('{ "a": 0, "b": 1 }', function(prop, v) { + if (first === "unset") + { + first = prop; + var second = (prop === "a") ? "b" : "a"; + + proxyObj = newGlobal().evaluate("({ c: 42, d: 17 })"); + Object.defineProperty(this, second, { value: proxyObj }); + } + return v; +}); + +if (first === "a") +{ + assertEq(obj.a, 0); + assertEq(obj.b, proxyObj); + assertEq(obj.b.c, 42); + assertEq(obj.b.d, 17); +} +else +{ + assertEq(obj.a, proxyObj); + assertEq(obj.a.c, 42); + assertEq(obj.a.d, 17); + assertEq(obj.b, 1); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/reviver-mutates-holder-object-nonnative.js b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-object-nonnative.js new file mode 100644 index 000000000..1300f8dd0 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-object-nonnative.js @@ -0,0 +1,60 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden <jwalden+code@mit.edu> + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 901380; +var summary = "Behavior when JSON.parse walks over a non-native object"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// A little trickiness to account for the undefined-ness of property +// enumeration order. +var first = "unset"; + +var observedTypedArrayElementCount = 0; + +var typedArray = null; + +var obj = JSON.parse('{ "a": 0, "b": 1 }', function(prop, v) { + if (first === "unset") + { + first = prop; + var second = (prop === "a") ? "b" : "a"; + typedArray = new Int8Array(1); + Object.defineProperty(this, second, { value: typedArray }); + } + if (this instanceof Int8Array) + { + assertEq(prop, "0"); + observedTypedArrayElementCount++; + } + return v; +}); + +if (first === "a") +{ + assertEq(obj.a, 0); + assertEq(obj.b, typedArray); +} +else +{ + assertEq(obj.a, typedArray); + assertEq(obj.b, 1); +} + +assertEq(observedTypedArrayElementCount, 1); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/reviver-mutates-holder-object.js b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-object.js new file mode 100644 index 000000000..973766e9a --- /dev/null +++ b/js/src/tests/ecma_5/extensions/reviver-mutates-holder-object.js @@ -0,0 +1,56 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden <jwalden+code@mit.edu> + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 901351; +var summary = "Behavior when the JSON.parse reviver mutates the holder object"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// A little trickiness to account for the undefined-ness of property +// enumeration order. +var first = "unset"; + +var proxyObj = null; + +var obj = JSON.parse('{ "a": 0, "b": 1 }', function(prop, v) { + if (first === "unset") + { + first = prop; + var second = (prop === "a") ? "b" : "a"; + + proxyObj = new Proxy({ c: 42, d: 17 }, {}); + Object.defineProperty(this, second, { value: proxyObj }); + } + return v; +}); + +if (first === "a") +{ + assertEq(obj.a, 0); + assertEq(obj.b, proxyObj); + assertEq(obj.b.c, 42); + assertEq(obj.b.d, 17); +} +else +{ + assertEq(obj.a, proxyObj); + assertEq(obj.a.c, 42); + assertEq(obj.a.d, 17); + assertEq(obj.b, 1); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/extensions/shell.js b/js/src/tests/ecma_5/extensions/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_5/extensions/shell.js diff --git a/js/src/tests/ecma_5/extensions/strict-function-statements.js b/js/src/tests/ecma_5/extensions/strict-function-statements.js new file mode 100644 index 000000000..e6dc15139 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/strict-function-statements.js @@ -0,0 +1,94 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +// Ordinary function definitions should be unaffected. +assertEq(testLenientAndStrict("function f() { }", + parsesSuccessfully, + parsesSuccessfully), + true); + +// Lambdas are always permitted within blocks. +assertEq(testLenientAndStrict("{ (function f() { }) }", + parsesSuccessfully, + parsesSuccessfully), + true); + +// Function statements within unbraced blocks are forbidden in strict mode code. +// They are allowed only under if statements in sloppy mode. +assertEq(testLenientAndStrict("if (true) function f() { }", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); +assertEq(testLenientAndStrict("while (true) function f() { }", + parseRaisesException(SyntaxError), + parseRaisesException(SyntaxError)), + true); +assertEq(testLenientAndStrict("do function f() { } while (true);", + parseRaisesException(SyntaxError), + parseRaisesException(SyntaxError)), + true); +assertEq(testLenientAndStrict("for(;;) function f() { }", + parseRaisesException(SyntaxError), + parseRaisesException(SyntaxError)), + true); +assertEq(testLenientAndStrict("for(x in []) function f() { }", + parseRaisesException(SyntaxError), + parseRaisesException(SyntaxError)), + true); +assertEq(testLenientAndStrict("with(o) function f() { }", + parseRaisesException(SyntaxError), + parseRaisesException(SyntaxError)), + true); +assertEq(testLenientAndStrict("switch(1) { case 1: function f() { } }", + parsesSuccessfully, + parsesSuccessfully), + true); +assertEq(testLenientAndStrict("x: function f() { }", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); +assertEq(testLenientAndStrict("try { function f() { } } catch (x) { }", + parsesSuccessfully, + parsesSuccessfully), + true); + +// Lambdas are always permitted within any sort of statement. +assertEq(testLenientAndStrict("if (true) (function f() { })", + parsesSuccessfully, + parsesSuccessfully), + true); + +// Function statements are permitted in blocks within lenient functions. +assertEq(parsesSuccessfully("function f() { function g() { } }"), + true); + +// Function statements are permitted in if statement within lenient functions. +assertEq(parsesSuccessfully("function f() { if (true) function g() { } }"), + true); + +assertEq(parseRaisesException(SyntaxError) + ("function f() { 'use strict'; if (true) function g() { } }"), + true); + +assertEq(parsesSuccessfully("function f() { 'use strict'; { function g() { } } }"), + true); + +assertEq(parsesSuccessfully("function f() { 'use strict'; if (true) (function g() { }) }"), + true); + +assertEq(parsesSuccessfully("function f() { 'use strict'; { (function g() { }) } }"), + true); + +// Eval should behave the same way. (The parse-only tests use the Function constructor.) +assertEq(testLenientAndStrict("function f() { }", + completesNormally, + completesNormally), + true); +assertEq(testLenientAndStrict("{ function f() { } }", + completesNormally, + completesNormally), + true); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/strict-function-toSource.js b/js/src/tests/ecma_5/extensions/strict-function-toSource.js new file mode 100644 index 000000000..6d9b68560 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/strict-function-toSource.js @@ -0,0 +1,17 @@ +/* + * Bug 800407 - Functions defined with Function construcor + * do have strict mode when JSOPTION_STRICT_MODE is on. + */ + +options("strict_mode"); +function testRunOptionStrictMode(str, arg, result) { + var strict_inner = new Function('return typeof this == "undefined";'); + return strict_inner; +} +let inner = testRunOptionStrictMode(); +assertEq(inner(), true); +assertEq(eval(uneval(inner))(), true); + +assertEq((new Function('x', 'return x*2;')).toSource().includes('"use strict"'), false); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/strict-option-redeclared-parameter.js b/js/src/tests/ecma_5/extensions/strict-option-redeclared-parameter.js new file mode 100644 index 000000000..5a36b6947 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/strict-option-redeclared-parameter.js @@ -0,0 +1,30 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 630770; +var summary = + 'Correctly warn about duplicate parameters when the strict option is enabled'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// Verify that duplicate parameters, with the strict option set, don't provoke +// an assertion. Ideally we'd also verify that we warn exactly once per +// duplicated parameter name, but at present there's no way to test that +// without more effort (further customizing the shell JSErrorReporter) than we +// want to make now. +options("strict"); +eval("function a(x, x, x, x) { }"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/string-literal-getter-setter-decompilation.js b/js/src/tests/ecma_5/extensions/string-literal-getter-setter-decompilation.js new file mode 100644 index 000000000..a0a571405 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/string-literal-getter-setter-decompilation.js @@ -0,0 +1,34 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +var f; +try +{ + f = eval("(function literalInside() { return { set 'c d e'(v) { } }; })"); +} +catch (e) +{ + assertEq(true, false, + "string-literal property name in setter in object literal in " + + "function statement failed to parse: " + e); +} + +var fstr = "" + f; +assertEq(fstr.indexOf("set") < fstr.indexOf("c d e"), true, + "should be using new-style syntax with string literal in place of " + + "property identifier"); +assertEq(fstr.indexOf("setter") < 0, true, "using old-style syntax?"); + +var o = f(); +var ostr = "" + o; +assertEq("c d e" in o, true, "missing the property?"); +assertEq("set" in Object.getOwnPropertyDescriptor(o, "c d e"), true, + "'c d e' property not a setter?"); +// disabled because we still generate old-style syntax here (toSource +// decompilation is as yet unfixed) +// assertEq(ostr.indexOf("set") < ostr.indexOf("c d e"), true, +// "should be using new-style syntax when getting the source of a " + +// "getter/setter while decompiling an object"); +// assertEq(ostr.indexOf("setter") < 0, true, "using old-style syntax?"); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/toLocaleString-infinite-recursion.js b/js/src/tests/ecma_5/extensions/toLocaleString-infinite-recursion.js new file mode 100644 index 000000000..a11433ce4 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/toLocaleString-infinite-recursion.js @@ -0,0 +1,31 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 653789; +var summary = 'Check for too-deep stack when calling toLocaleString'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +try +{ + "" + { toString: Object.prototype.toLocaleString }; + throw new Error("should have thrown on over-recursion"); +} +catch (e) +{ + assertEq(e instanceof InternalError, true); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/toSource-infinite-recursion.js b/js/src/tests/ecma_5/extensions/toSource-infinite-recursion.js new file mode 100644 index 000000000..2ddcaa752 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/toSource-infinite-recursion.js @@ -0,0 +1,34 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 650574; +var summary = 'Check for too-deep stack when converting a value to source'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +try +{ + var e = Error(''); + e.fileName = e; + e.toSource(); + throw new Error("should have thrown"); +} +catch (e) +{ + assertEq(e instanceof InternalError, true, + "should have thrown for over-recursion"); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!"); diff --git a/js/src/tests/ecma_5/extensions/watch-array-length.js b/js/src/tests/ecma_5/extensions/watch-array-length.js new file mode 100644 index 000000000..e9b356efa --- /dev/null +++ b/js/src/tests/ecma_5/extensions/watch-array-length.js @@ -0,0 +1,41 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var hitCount; +function watcher(p,o,n) { hitCount++; return n; } + +var a = [1]; +a.watch('length', watcher); +hitCount = 0; +a.length = 0; +reportCompare(1, hitCount, "lenient; configurable: watchpoint hit"); + +var b = Object.defineProperty([1],'0',{configurable:false}); +b.watch('length', watcher); +hitCount = 0; +var result; +try { + b.length = 0; + result = "no error"; +} catch (x) { + result = x.toString(); +} +reportCompare(1, hitCount, "lenient; non-configurable: watchpoint hit"); +reportCompare(1, b.length, "lenient; non-configurable: length unchanged"); +reportCompare("no error", result, "lenient; non-configurable: no error thrown"); + +var c = Object.defineProperty([1],'0',{configurable:false}); +c.watch('length', watcher); +hitCount = 0; +var threwTypeError; +try { + (function(){'use strict'; c.length = 0;})(); + threwTypeError = false; +} catch (x) { + threwTypeError = x instanceof TypeError; +} +reportCompare(1, hitCount, "strict; non-configurable: watchpoint hit"); +reportCompare(1, c.length, "strict; non-configurable: length unchanged"); +reportCompare(true, threwTypeError, "strict; non-configurable: TypeError thrown"); diff --git a/js/src/tests/ecma_5/extensions/watch-inherited-property.js b/js/src/tests/ecma_5/extensions/watch-inherited-property.js new file mode 100644 index 000000000..1a0ad566b --- /dev/null +++ b/js/src/tests/ecma_5/extensions/watch-inherited-property.js @@ -0,0 +1,38 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +/* Create a prototype object with a setter property. */ +var protoSetterCount; +var proto = ({ set x(v) { protoSetterCount++; } }); + +/* Put a watchpoint on that setter. */ +var protoWatchCount; +proto.watch('x', function() { protoWatchCount++; }); + +/* Make an object with the above as its prototype. */ +function C() { } +C.prototype = proto; +var o = new C(); + +/* + * Set a watchpoint on the property in the inheriting object. We have + * defined this to mean "duplicate the property, setter and all, in the + * inheriting object." I don't think debugging observation mechanisms + * should mutate the program being run, but that's what we've got. + */ +var oWatchCount; +o.watch('x', function() { oWatchCount++; }); + +/* + * Assign to the property. This should trip the watchpoint on the inheriting object and + * the setter. + */ +protoSetterCount = protoWatchCount = oWatchCount = 0; +o.x = 1; +assertEq(protoWatchCount, 0); +assertEq(oWatchCount, 1); +assertEq(protoSetterCount, 1); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/watch-replaced-setter.js b/js/src/tests/ecma_5/extensions/watch-replaced-setter.js new file mode 100644 index 000000000..05cf60aff --- /dev/null +++ b/js/src/tests/ecma_5/extensions/watch-replaced-setter.js @@ -0,0 +1,46 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +/* A stock watcher function. */ +var watcherCount; +function watcher(id, oldval, newval) { watcherCount++; return newval; } + +/* Create an object with a JavaScript setter. */ +var setterCount; +var o = { w:2, set x(v) { setterCount++; } }; + +/* + * Put the object in dictionary mode, so that JSObject::putProperty will + * mutate its shapes instead of creating new ones. + */ +delete o.w; + +/* + * Place a watchpoint on the property. The watchpoint structure holds the + * original JavaScript setter, and a pointer to the shape. + */ +o.watch('x', watcher); + +/* + * Replace the accessor property with a value property. The shape's setter + * should become a non-JS setter, js_watch_set, and the watchpoint + * structure's saved setter should be updated (in this case, cleared). + */ +Object.defineProperty(o, 'x', { value:3, + writable:true, + enumerable:true, + configurable:true }); + +/* + * Assign to the property. This should trigger js_watch_set, which should + * call the handler, and then see that there is no JS-level setter to pass + * control on to, and return. + */ +watcherCount = setterCount = 0; +o.x = 3; +assertEq(watcherCount, 1); +assertEq(setterCount, 0); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/watch-setter-become-setter.js b/js/src/tests/ecma_5/extensions/watch-setter-become-setter.js new file mode 100644 index 000000000..f5eff98b8 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/watch-setter-become-setter.js @@ -0,0 +1,44 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +/* Create an object with a JavaScript setter. */ +var firstSetterCount; +var o = { w:2, set x(v) { firstSetterCount++; } }; + +/* + * Put the object in dictionary mode, so that JSObject::putProperty will + * mutate its shapes instead of creating new ones. + */ +delete o.w; + +/* A stock watcher function. */ +var watcherCount; +function watcher(id, oldval, newval) { watcherCount++; return newval; } + +/* + * Place a watchpoint on the property. The property's shape now has the + * watchpoint setter, with the original setter saved in the watchpoint + * structure. + */ +o.watch('x', watcher); + +/* + * Replace the setter with a new setter. The shape should get updated to + * refer to the new setter, and then the watchpoint setter should be + * re-established. + */ +var secondSetterCount; +Object.defineProperty(o, 'x', { set: function () { secondSetterCount++ } }); + +/* + * Assign to the property. This should trigger the watchpoint and the new setter. + */ +watcherCount = firstSetterCount = secondSetterCount = 0; +o.x = 3; +assertEq(watcherCount, 1); +assertEq(firstSetterCount, 0); +assertEq(secondSetterCount, 1); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js b/js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js new file mode 100644 index 000000000..03cdd788e --- /dev/null +++ b/js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js @@ -0,0 +1,43 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +/* A stock watcher function. */ +var watcherCount; +function watcher(id, old, newval) { + watcherCount++; + return newval; +} + +/* Create an object with a value property. */ +var o = { w:2, x:3 }; + +/* + * Place a watchpoint on the value property. The watchpoint structure holds + * the original JavaScript setter, and a pointer to the shape. + */ +o.watch('x', watcher); + +/* + * Put the object in dictionary mode, so that JSObject::putProperty will + * mutate its shapes instead of creating new ones. + */ +delete o.w; + +/* + * Replace the value property with a setter. + */ +var setterCount; +o.__defineSetter__('x', function() { setterCount++; }); + +/* + * Trigger the watchpoint. The watchpoint handler should run, and then the + * setter should run. + */ +watcherCount = setterCount = 0; +o.x = 4; +assertEq(watcherCount, 1); +assertEq(setterCount, 1); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js b/js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js new file mode 100644 index 000000000..85410bbd4 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js @@ -0,0 +1,56 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +function make_watcher(name) { + return function (id, oldv, newv) { + print("watched " + name + "[0]"); + }; +} + +var o, p; +function f(flag) { + if (flag) { + o = arguments; + } else { + p = arguments; + o.watch(0, make_watcher('o')); + p.watch(0, make_watcher('p')); + + /* + * Previously, the watchpoint implementation actually substituted its magic setter + * functions for the setters of shared shapes, and then 1) carefully ignored calls + * to its magic setter from unrelated objects, and 2) avoided restoring the + * original setter until all watchpoints on that shape had been removed. + * + * However, when the watchpoint code began using JSObject::changeProperty and + * js_ChangeNativePropertyAttrs to change shapes' setters, the shape tree code + * became conscious of the presence of watchpoints, and shared shapes between + * objects only when their watchpoint nature coincided. Clearing the magic setter + * from one object's shape would not affect other objects, because the + * watchpointed and non-watchpointed shapes were distinct if they were shared. + * + * Thus, the first unwatch call must go ahead and fix p's shape, even though a + * watchpoint exists on the same shape in o. o's watchpoint's presence shouldn't + * cause 'unwatch' to leave p's magic setter in place. + */ + + /* DropWatchPointAndUnlock would see o's watchpoint, and not change p's property. */ + p.unwatch(0); + + /* DropWatchPointAndUnlock would fix o's property, but not p's; p's setter would be gone. */ + o.unwatch(0); + + /* This would fail to invoke the arguments object's setter. */ + p[0] = 4; + + /* And the formal parameter would not get updated. */ + assertEq(flag, 4); + } +} + +f(true); +f(false); + +reportCompare(true, true); |