219 lines
9.4 KiB
JavaScript
219 lines
9.4 KiB
JavaScript
/* 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/. */
|
|
|
|
|
|
if (typeof assertThrowsInstanceOf === 'undefined') {
|
|
var 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);
|
|
};
|
|
}
|
|
|
|
if (typeof assertThrowsValue === 'undefined') {
|
|
var 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 assertDeepEq === 'undefined') {
|
|
var assertDeepEq = (function(){
|
|
var call = Function.prototype.call,
|
|
Array_isArray = Array.isArray,
|
|
Map_ = Map,
|
|
Error_ = Error,
|
|
Symbol_ = Symbol,
|
|
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,
|
|
uneval_ = uneval;
|
|
|
|
// 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 " + uneval_(na) + ", expected " + uneval_(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
|
|
: "[" + uneval_(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]]"));
|
|
}
|
|
}
|
|
};
|
|
|
|
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 " + uneval_(a) + ", expected " + uneval_(b) + " " + path);
|
|
} else if (uneval_(a) !== uneval_(b)) {
|
|
// We lamely use uneval_ to distinguish well-known symbols
|
|
// from user-created symbols. The standard doesn't offer
|
|
// a convenient way to do it.
|
|
throw Error_("got " + uneval_(a) + ", expected " + uneval_(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 " + uneval_(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, "");
|
|
};
|
|
})();
|
|
}
|
|
|
|
if (typeof assertWarning === 'undefined') {
|
|
function assertWarning(func, name) {
|
|
enableLastWarning();
|
|
func();
|
|
var warning = getLastWarning();
|
|
assertEq(warning !== null, true);
|
|
assertEq(warning.name, name);
|
|
disableLastWarning();
|
|
}
|
|
}
|