diff options
Diffstat (limited to '')
-rw-r--r-- | devtools/shared/heapsnapshot/tests/xpcshell/Match.sys.mjs | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/devtools/shared/heapsnapshot/tests/xpcshell/Match.sys.mjs b/devtools/shared/heapsnapshot/tests/xpcshell/Match.sys.mjs new file mode 100644 index 0000000000..76312db86a --- /dev/null +++ b/devtools/shared/heapsnapshot/tests/xpcshell/Match.sys.mjs @@ -0,0 +1,218 @@ +// A little pattern-matching library. +// +// Ported from js/src/tests/js1_8_5/reflect-parse/Match.js for use with devtools +// server xpcshell tests. + +export const Match = (function () { + function Pattern(template) { + // act like a constructor even as a function + if (!(this instanceof Pattern)) { + return new Pattern(template); + } + + this.template = template; + } + + Pattern.prototype = { + match(act) { + return match(act, this.template); + }, + + matches(act) { + try { + return this.match(act); + } catch (e) { + if (e instanceof MatchError) { + return false; + } + } + return false; + }, + + assert(act, message) { + try { + return this.match(act); + } catch (e) { + if (e instanceof MatchError) { + throw new Error((message || "failed match") + ": " + e.message); + } + } + return false; + }, + + toString: () => "[object Pattern]", + }; + + Pattern.ANY = new Pattern(); + Pattern.ANY.template = Pattern.ANY; + + Pattern.NUMBER = new Pattern(); + Pattern.NUMBER.match = function (act) { + if (typeof act !== "number") { + throw new MatchError("Expected number, got: " + quote(act)); + } + }; + + Pattern.NATURAL = new Pattern(); + Pattern.NATURAL.match = function (act) { + if (typeof act !== "number" || act !== Math.floor(act) || act < 0) { + throw new MatchError("Expected natural number, got: " + quote(act)); + } + }; + + const quote = uneval; + + function MatchError(msg) { + this.message = msg; + } + + MatchError.prototype = { + toString() { + return "match error: " + this.message; + }, + }; + + function isAtom(x) { + return ( + typeof x === "number" || + typeof x === "string" || + typeof x === "boolean" || + x === null || + (typeof x === "object" && x instanceof RegExp) + ); + } + + function isObject(x) { + return x !== null && typeof x === "object"; + } + + function isFunction(x) { + return typeof x === "function"; + } + + function isArrayLike(x) { + return isObject(x) && "length" in x; + } + + function matchAtom(act, exp) { + if (typeof exp === "number" && isNaN(exp)) { + if (typeof act !== "number" || !isNaN(act)) { + throw new MatchError("expected NaN, got: " + quote(act)); + } + return true; + } + + if (exp === null) { + if (act !== null) { + throw new MatchError("expected null, got: " + quote(act)); + } + return true; + } + + if (exp instanceof RegExp) { + if (!(act instanceof RegExp) || exp.source !== act.source) { + throw new MatchError("expected " + quote(exp) + ", got: " + quote(act)); + } + return true; + } + + switch (typeof exp) { + case "string": + if (act !== exp) { + throw new MatchError( + "expected " + quote(exp) + ", got " + quote(act) + ); + } + return true; + case "boolean": + case "number": + if (exp !== act) { + throw new MatchError("expected " + exp + ", got " + quote(act)); + } + return true; + } + + throw new Error("bad pattern: " + exp.toSource()); + } + + function matchObject(act, exp) { + if (!isObject(act)) { + throw new MatchError("expected object, got " + quote(act)); + } + + for (const key in exp) { + if (!(key in act)) { + throw new MatchError( + "expected property " + quote(key) + " not found in " + quote(act) + ); + } + match(act[key], exp[key]); + } + + return true; + } + + function matchFunction(act, exp) { + if (!isFunction(act)) { + throw new MatchError("expected function, got " + quote(act)); + } + + if (act !== exp) { + throw new MatchError( + "expected function: " + exp + "\nbut got different function: " + act + ); + } + } + + function matchArray(act, exp) { + if (!isObject(act) || !("length" in act)) { + throw new MatchError("expected array-like object, got " + quote(act)); + } + + const length = exp.length; + if (act.length !== exp.length) { + throw new MatchError( + "expected array-like object of length " + length + ", got " + quote(act) + ); + } + + for (let i = 0; i < length; i++) { + if (i in exp) { + if (!(i in act)) { + throw new MatchError( + "expected array property " + i + " not found in " + quote(act) + ); + } + match(act[i], exp[i]); + } + } + + return true; + } + + function match(act, exp) { + if (exp === Pattern.ANY) { + return true; + } + + if (exp instanceof Pattern) { + return exp.match(act); + } + + if (isAtom(exp)) { + return matchAtom(act, exp); + } + + if (isArrayLike(exp)) { + return matchArray(act, exp); + } + + if (isFunction(exp)) { + return matchFunction(act, exp); + } + + return matchObject(act, exp); + } + + return { Pattern, MatchError }; +})(); |