зеркало из https://github.com/mozilla/gecko-dev.git
Bug 866849, part 1 - Add assertEqual testing function in jit-test/lib/asserts.js. r=evilpies.
This commit is contained in:
Родитель
570118e565
Коммит
b534f33ea6
|
@ -99,3 +99,134 @@ if (typeof assertNoWarning === 'undefined') {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof assertDeepEq === 'undefined') {
|
||||||
|
let call = Function.prototype.call,
|
||||||
|
Map_ = Map,
|
||||||
|
Error_ = Error,
|
||||||
|
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"`.
|
||||||
|
let isPrimitive = v =>
|
||||||
|
v === null ||
|
||||||
|
v === undefined ||
|
||||||
|
typeof v === "boolean" ||
|
||||||
|
typeof v === "number" ||
|
||||||
|
typeof v === "string" ||
|
||||||
|
typeof v === "symbol";
|
||||||
|
|
||||||
|
let assertSameValue = (a, b, msg) => {
|
||||||
|
try {
|
||||||
|
assertEq(a, b);
|
||||||
|
} catch (exc) {
|
||||||
|
throw new Error(exc.message + (msg ? " " + msg : ""));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let assertSameClass = (a, b, msg) => {
|
||||||
|
var ac = Object_toString(a), bc = Object_toString(b);
|
||||||
|
assertSameValue(ac, bc, msg);
|
||||||
|
switch (ac) {
|
||||||
|
case "[object Function]":
|
||||||
|
assertSameValue(Function_toString(a), Function_toString(b), msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let at = (prevmsg, segment) => 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.
|
||||||
|
//
|
||||||
|
var assertDeepEq = function assertDeepEq(a, b, options) {
|
||||||
|
let strictEquivalence = options ? options.strictEquivalence : false;
|
||||||
|
|
||||||
|
let assertSameProto = (a, b, msg) => {
|
||||||
|
check(Object_getPrototypeOf(a), Object_getPrototypeOf(b), at(msg, ".__proto__"))
|
||||||
|
};
|
||||||
|
|
||||||
|
let failPropList = (na, nb, msg) => {
|
||||||
|
throw Error_("got own properties " + uneval_(na) + ", expected " + uneval_(nb) +
|
||||||
|
(msg ? " " + msg : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
let assertSameProps = (a, b, msg) => {
|
||||||
|
var na = Object_getOwnPropertyNames(a),
|
||||||
|
nb = Object_getOwnPropertyNames(b);
|
||||||
|
if (na.length !== nb.length)
|
||||||
|
failPropList(na, nb, msg);
|
||||||
|
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 = Map_();
|
||||||
|
var bpath = Map_();
|
||||||
|
|
||||||
|
let check = (a, b, path) => {
|
||||||
|
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, "");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
// Tests for the assertEqual function in jit-test/lib/asserts.js
|
||||||
|
|
||||||
|
load(libdir + "asserts.js");
|
||||||
|
|
||||||
|
function assertNotDeepEq(a, b, options) {
|
||||||
|
assertThrowsInstanceOf(() => assertDeepEq(a, b, options), Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// primitives
|
||||||
|
assertDeepEq(undefined, undefined);
|
||||||
|
assertDeepEq("1", "1");
|
||||||
|
assertNotDeepEq(1, "1");
|
||||||
|
assertNotDeepEq(undefined, null);
|
||||||
|
assertNotDeepEq({}, null);
|
||||||
|
|
||||||
|
// objects
|
||||||
|
assertDeepEq({}, {});
|
||||||
|
assertDeepEq({one: 1, two: 2}, {one: 1, two: 2});
|
||||||
|
assertNotDeepEq(Object.freeze({}), {});
|
||||||
|
assertDeepEq(Object.create(null), Object.create(null));
|
||||||
|
assertNotDeepEq(Object.create(null, {a: {configurable: false, value: 3}}),
|
||||||
|
Object.create(null, {a: {configurable: true, value: 3}}));
|
||||||
|
assertNotDeepEq({one: 1}, {one: 1, two: 2});
|
||||||
|
assertNotDeepEq({yes: true}, {oui: true});
|
||||||
|
assertNotDeepEq({zero: 0}, {zero: "0"});
|
||||||
|
|
||||||
|
// test the comment
|
||||||
|
var x = {}, y = {}, ax = [x];
|
||||||
|
assertDeepEq([ax, x], [ax, y]); // passes (bogusly)
|
||||||
|
assertNotDeepEq([ax, x], [ax, y], {strictEquivalence: true});
|
||||||
|
assertDeepEq([x, ax], [y, ax]); // passes (bogusly)
|
||||||
|
assertNotDeepEq([x, ax], [y, ax], {strictEquivalence: true});
|
||||||
|
|
||||||
|
// object identity
|
||||||
|
assertNotDeepEq([x, y], [x, x]);
|
||||||
|
assertDeepEq([x, y], [x, y]);
|
||||||
|
assertDeepEq([y, x], [x, y]);
|
||||||
|
|
||||||
|
// proto chain
|
||||||
|
var x = {};
|
||||||
|
assertDeepEq(Object.create(x), Object.create(x));
|
||||||
|
assertDeepEq(Object.create({}), Object.create({})); // equivalent but not identical proto objects
|
||||||
|
|
||||||
|
// arrays
|
||||||
|
assertDeepEq([], []);
|
||||||
|
assertNotDeepEq([], [1]);
|
||||||
|
assertDeepEq([1], [1]);
|
||||||
|
assertNotDeepEq([0], [1]);
|
||||||
|
assertDeepEq([1, 2, 3], [1, 2, 3]);
|
||||||
|
assertNotDeepEq([1, , 3], [1, undefined, 3]);
|
||||||
|
var p = [], q = [];
|
||||||
|
p.prop = 1;
|
||||||
|
assertNotDeepEq(p, q);
|
||||||
|
assertNotDeepEq(q, p);
|
||||||
|
q.prop = 1;
|
||||||
|
assertDeepEq(q, p);
|
||||||
|
|
||||||
|
// functions
|
||||||
|
assertNotDeepEq(() => 1, () => 2);
|
||||||
|
assertNotDeepEq((...x) => 1, x => 1);
|
||||||
|
assertNotDeepEq(function f(){}, function g(){});
|
||||||
|
var f1 = function () {}, f2 = function () {};
|
||||||
|
assertDeepEq(f1, f1);
|
||||||
|
assertDeepEq(f1, f2); // same text, close enough
|
||||||
|
f1.prop = 1;
|
||||||
|
assertNotDeepEq(f1, f2);
|
||||||
|
f2.prop = 1;
|
||||||
|
assertDeepEq(f1, f2);
|
||||||
|
|
||||||
|
// recursion
|
||||||
|
var a = [], b = [];
|
||||||
|
a[0] = a;
|
||||||
|
b[0] = b;
|
||||||
|
assertDeepEq(a, b);
|
||||||
|
a[0] = b;
|
||||||
|
assertNotDeepEq(a, b); // [#1=[#1#]] is not structurally equivalent to #1=[[#1#]]
|
||||||
|
b[0] = a;
|
||||||
|
assertDeepEq(a, b);
|
||||||
|
b[0] = [a]; // a[0] === b, b[0] === c, c[0] === a
|
||||||
|
assertDeepEq(a, b);
|
||||||
|
|
||||||
|
// objects that merge
|
||||||
|
var x = {};
|
||||||
|
assertDeepEq({x: x}, {x: x});
|
||||||
|
var y = [x];
|
||||||
|
assertDeepEq([y], [y]);
|
||||||
|
|
||||||
|
// cross-compartment
|
||||||
|
var g1 = newGlobal(), g2 = newGlobal();
|
||||||
|
assertDeepEq(g1, g2);
|
||||||
|
assertDeepEq(g1, g2, {strictEquivalence: true});
|
||||||
|
Object.preventExtensions(g2.Math.abs); // make some miniscule change
|
||||||
|
assertNotDeepEq(g1, g2);
|
Загрузка…
Ссылка в новой задаче