summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/shell.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/non262/shell.js')
-rw-r--r--js/src/tests/non262/shell.js339
1 files changed, 339 insertions, 0 deletions
diff --git a/js/src/tests/non262/shell.js b/js/src/tests/non262/shell.js
new file mode 100644
index 0000000000..2e4f9e5224
--- /dev/null
+++ b/js/src/tests/non262/shell.js
@@ -0,0 +1,339 @@
+/* -*- 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/. */
+
+(function(global) {
+ const undefined = void 0;
+
+ /*
+ * completesNormally(CODE) returns true if evaluating CODE (as eval
+ * code) completes normally (rather than throwing an exception).
+ */
+ global.completesNormally = function completesNormally(code) {
+ try {
+ eval(code);
+ return true;
+ } catch (exception) {
+ return false;
+ }
+ }
+
+ /*
+ * raisesException(EXCEPTION)(CODE) returns true if evaluating CODE (as
+ * eval code) throws an exception object that is an instance of EXCEPTION,
+ * and returns false if it throws any other error or evaluates
+ * successfully. For example: raises(TypeError)("0()") == true.
+ */
+ global.raisesException = function raisesException(exception) {
+ return function (code) {
+ try {
+ eval(code);
+ return false;
+ } catch (actual) {
+ return actual instanceof exception;
+ }
+ };
+ };
+
+ /*
+ * Return true if A is equal to B, where equality on arrays and objects
+ * means that they have the same set of enumerable properties, the values
+ * of each property are deep_equal, and their 'length' properties are
+ * equal. Equality on other types is ==.
+ */
+ global.deepEqual = function deepEqual(a, b) {
+ if (typeof a != typeof b)
+ return false;
+
+ if (typeof a == 'object') {
+ var props = {};
+ // For every property of a, does b have that property with an equal value?
+ for (var prop in a) {
+ if (!deepEqual(a[prop], b[prop]))
+ return false;
+ props[prop] = true;
+ }
+ // Are all of b's properties present on a?
+ for (var prop in b)
+ if (!props[prop])
+ return false;
+ // length isn't enumerable, but we want to check it, too.
+ return a.length == b.length;
+ }
+
+ if (a === b) {
+ // Distinguish 0 from -0, even though they are ===.
+ return a !== 0 || 1/a === 1/b;
+ }
+
+ // Treat NaNs as equal, even though NaN !== NaN.
+ // NaNs are the only non-reflexive values, i.e., if a !== a, then a is a NaN.
+ // isNaN is broken: it converts its argument to number, so isNaN("foo") => true
+ return a !== a && b !== b;
+ }
+
+ /** Make an iterator with a return method. */
+ global.makeIterator = function makeIterator(overrides) {
+ var throwMethod;
+ if (overrides && overrides.throw)
+ throwMethod = overrides.throw;
+ var iterator = {
+ throw: throwMethod,
+ next: function(x) {
+ if (overrides && overrides.next)
+ return overrides.next(x);
+ return { done: false };
+ },
+ return: function(x) {
+ if (overrides && overrides.ret)
+ return overrides.ret(x);
+ return { done: true };
+ }
+ };
+
+ return function() { return iterator; };
+ };
+
+ /** Yield every permutation of the elements in some array. */
+ global.Permutations = function* Permutations(items) {
+ if (items.length == 0) {
+ yield [];
+ } else {
+ items = items.slice(0);
+ for (let i = 0; i < items.length; i++) {
+ let swap = items[0];
+ items[0] = items[i];
+ items[i] = swap;
+ for (let e of Permutations(items.slice(1, items.length)))
+ yield [items[0]].concat(e);
+ }
+ }
+ };
+
+ if (typeof global.assertThrowsValue === 'undefined') {
+ global.assertThrowsValue = function assertThrowsValue(f, val, msg) {
+ var fullmsg;
+ try {
+ f();
+ } catch (exc) {
+ if ((exc === val) === (val === val) && (val !== 0 || 1 / exc === 1 / val))
+ return;
+ fullmsg = "Assertion failed: expected exception " + val + ", got " + exc;
+ }
+ if (fullmsg === undefined)
+ fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown";
+ if (msg !== undefined)
+ fullmsg += " - " + msg;
+ throw new Error(fullmsg);
+ };
+ }
+
+ if (typeof global.assertThrowsInstanceOf === 'undefined') {
+ global.assertThrowsInstanceOf = function assertThrowsInstanceOf(f, ctor, msg) {
+ var fullmsg;
+ try {
+ f();
+ } catch (exc) {
+ if (exc instanceof ctor)
+ return;
+ fullmsg = `Assertion failed: expected exception ${ctor.name}, got ${exc}`;
+ }
+
+ if (fullmsg === undefined)
+ fullmsg = `Assertion failed: expected exception ${ctor.name}, no exception thrown`;
+ if (msg !== undefined)
+ fullmsg += " - " + msg;
+
+ throw new Error(fullmsg);
+ };
+ }
+
+ global.assertDeepEq = (function(){
+ var call = Function.prototype.call,
+ Array_isArray = Array.isArray,
+ Array_includes = call.bind(Array.prototype.includes),
+ Map_ = Map,
+ Error_ = Error,
+ Symbol_ = Symbol,
+ Symbol_keyFor = Symbol.keyFor,
+ Symbol_description = call.bind(Object.getOwnPropertyDescriptor(Symbol.prototype, "description").get),
+ Map_has = call.bind(Map.prototype.has),
+ Map_get = call.bind(Map.prototype.get),
+ Map_set = call.bind(Map.prototype.set),
+ Object_toString = call.bind(Object.prototype.toString),
+ Function_toString = call.bind(Function.prototype.toString),
+ Object_getPrototypeOf = Object.getPrototypeOf,
+ Object_hasOwnProperty = call.bind(Object.prototype.hasOwnProperty),
+ Object_getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor,
+ Object_isExtensible = Object.isExtensible,
+ Object_getOwnPropertyNames = Object.getOwnPropertyNames;
+
+ // Return true iff ES6 Type(v) isn't Object.
+ // Note that `typeof document.all === "undefined"`.
+ function isPrimitive(v) {
+ return (v === null ||
+ v === undefined ||
+ typeof v === "boolean" ||
+ typeof v === "number" ||
+ typeof v === "string" ||
+ typeof v === "symbol");
+ }
+
+ function assertSameValue(a, b, msg) {
+ try {
+ assertEq(a, b);
+ } catch (exc) {
+ throw Error_(exc.message + (msg ? " " + msg : ""));
+ }
+ }
+
+ function assertSameClass(a, b, msg) {
+ var ac = Object_toString(a), bc = Object_toString(b);
+ assertSameValue(ac, bc, msg);
+ switch (ac) {
+ case "[object Function]":
+ if (typeof isProxy !== "undefined" && !isProxy(a) && !isProxy(b))
+ assertSameValue(Function_toString(a), Function_toString(b), msg);
+ }
+ }
+
+ function at(prevmsg, segment) {
+ return prevmsg ? prevmsg + segment : "at _" + segment;
+ }
+
+ // Assert that the arguments a and b are thoroughly structurally equivalent.
+ //
+ // For the sake of speed, we cut a corner:
+ // var x = {}, y = {}, ax = [x];
+ // assertDeepEq([ax, x], [ax, y]); // passes (?!)
+ //
+ // Technically this should fail, since the two object graphs are different.
+ // (The graph of [ax, y] contains one more object than the graph of [ax, x].)
+ //
+ // To get technically correct behavior, pass {strictEquivalence: true}.
+ // This is slower because we have to walk the entire graph, and Object.prototype
+ // is big.
+ //
+ return function assertDeepEq(a, b, options) {
+ var strictEquivalence = options ? options.strictEquivalence : false;
+
+ function assertSameProto(a, b, msg) {
+ check(Object_getPrototypeOf(a), Object_getPrototypeOf(b), at(msg, ".__proto__"));
+ }
+
+ function failPropList(na, nb, msg) {
+ throw Error_("got own properties " + JSON.stringify(na) + ", expected " + JSON.stringify(nb) +
+ (msg ? " " + msg : ""));
+ }
+
+ function assertSameProps(a, b, msg) {
+ var na = Object_getOwnPropertyNames(a),
+ nb = Object_getOwnPropertyNames(b);
+ if (na.length !== nb.length)
+ failPropList(na, nb, msg);
+
+ // Ignore differences in whether Array elements are stored densely.
+ if (Array_isArray(a)) {
+ na.sort();
+ nb.sort();
+ }
+
+ for (var i = 0; i < na.length; i++) {
+ var name = na[i];
+ if (name !== nb[i])
+ failPropList(na, nb, msg);
+ var da = Object_getOwnPropertyDescriptor(a, name),
+ db = Object_getOwnPropertyDescriptor(b, name);
+ var pmsg = at(msg, /^[_$A-Za-z0-9]+$/.test(name)
+ ? /0|[1-9][0-9]*/.test(name) ? "[" + name + "]" : "." + name
+ : "[" + JSON.stringify(name) + "]");
+ assertSameValue(da.configurable, db.configurable, at(pmsg, ".[[Configurable]]"));
+ assertSameValue(da.enumerable, db.enumerable, at(pmsg, ".[[Enumerable]]"));
+ if (Object_hasOwnProperty(da, "value")) {
+ if (!Object_hasOwnProperty(db, "value"))
+ throw Error_("got data property, expected accessor property" + pmsg);
+ check(da.value, db.value, pmsg);
+ } else {
+ if (Object_hasOwnProperty(db, "value"))
+ throw Error_("got accessor property, expected data property" + pmsg);
+ check(da.get, db.get, at(pmsg, ".[[Get]]"));
+ check(da.set, db.set, at(pmsg, ".[[Set]]"));
+ }
+ }
+ };
+
+ const wellKnownSymbols = Reflect.ownKeys(Symbol)
+ .map(key => Symbol[key])
+ .filter(value => typeof value === "symbol");
+
+ // The standard doesn't offer a convenient way to distinguish well-known
+ // symbols from user-created symbols.
+ function isSimilarSymbol(a, b) {
+ // Fast path for same symbols.
+ if (a === b) {
+ return true;
+ }
+
+ // 1. Symbol descriptions must match.
+ // 2. Either both symbols are in the registry or none is.
+ // 3. Neither symbol must be a well-known symbol, because those are
+ // already handled through the fast path.
+ return Symbol_description(a) === Symbol_description(b) &&
+ Symbol_keyFor(a) === Symbol_keyFor(b) &&
+ !Array_includes(wellKnownSymbols, a) &&
+ !Array_includes(wellKnownSymbols, b);
+ }
+
+ var ab = new Map_();
+ var bpath = new Map_();
+
+ function check(a, b, path) {
+ if (typeof a === "symbol") {
+ // Symbols are primitives, but they have identity.
+ // Symbol("x") !== Symbol("x") but
+ // assertDeepEq(Symbol("x"), Symbol("x")) should pass.
+ if (typeof b !== "symbol") {
+ throw Error_("got " + String(a) + ", expected " + String(b) + " " + path);
+ } else if (!isSimilarSymbol(a, b)) {
+ throw Error_("got " + String(a) + ", expected " + String(b) + " " + path);
+ } else if (Map_has(ab, a)) {
+ assertSameValue(Map_get(ab, a), b, path);
+ } else if (Map_has(bpath, b)) {
+ var bPrevPath = Map_get(bpath, b) || "_";
+ throw Error_("got distinct symbols " + at(path, "") + " and " +
+ at(bPrevPath, "") + ", expected the same symbol both places");
+ } else {
+ Map_set(ab, a, b);
+ Map_set(bpath, b, path);
+ }
+ } else if (isPrimitive(a)) {
+ assertSameValue(a, b, path);
+ } else if (isPrimitive(b)) {
+ throw Error_("got " + Object_toString(a) + ", expected " + String(b) + " " + path);
+ } else if (Map_has(ab, a)) {
+ assertSameValue(Map_get(ab, a), b, path);
+ } else if (Map_has(bpath, b)) {
+ var bPrevPath = Map_get(bpath, b) || "_";
+ throw Error_("got distinct objects " + at(path, "") + " and " + at(bPrevPath, "") +
+ ", expected the same object both places");
+ } else {
+ Map_set(ab, a, b);
+ Map_set(bpath, b, path);
+ if (a !== b || strictEquivalence) {
+ assertSameClass(a, b, path);
+ assertSameProto(a, b, path);
+ assertSameProps(a, b, path);
+ assertSameValue(Object_isExtensible(a),
+ Object_isExtensible(b),
+ at(path, ".[[Extensible]]"));
+ }
+ }
+ }
+
+ check(a, b, "");
+ };
+ })();
+
+})(this);