diff options
Diffstat (limited to 'dom/heapsnapshot/tests/unit/Match.jsm')
-rw-r--r-- | dom/heapsnapshot/tests/unit/Match.jsm | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/dom/heapsnapshot/tests/unit/Match.jsm b/dom/heapsnapshot/tests/unit/Match.jsm new file mode 100644 index 0000000000..c29e6484e7 --- /dev/null +++ b/dom/heapsnapshot/tests/unit/Match.jsm @@ -0,0 +1,190 @@ +// A little pattern-matching library. +// +// Ported from js/src/tests/js1_8_5/reflect-parse/Match.js for use with devtools +// server xpcshell tests. + +this.EXPORTED_SYMBOLS = ["Match"]; + +this.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: function(act) { + return match(act, this.template); + }, + + matches: function(act) { + try { + return this.match(act); + } + catch (e if e instanceof MatchError) { + return false; + } + }, + + assert: function(act, message) { + try { + return this.match(act); + } + catch (e if e instanceof MatchError) { + throw new Error((message || "failed match") + ": " + e.message); + } + }, + + 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)); + } + } + + var quote = uneval; + + function MatchError(msg) { + this.message = msg; + } + + MatchError.prototype = { + toString: function() { + 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 (var 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)); + + var length = exp.length; + if (act.length !== exp.length) + throw new MatchError("expected array-like object of length " + length + ", got " + quote(act)); + + for (var 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: Pattern, + MatchError: MatchError }; + +})(); |