summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/lib/census.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/lib/census.js')
-rw-r--r--js/src/jit-test/lib/census.js161
1 files changed, 161 insertions, 0 deletions
diff --git a/js/src/jit-test/lib/census.js b/js/src/jit-test/lib/census.js
new file mode 100644
index 000000000..20be2e12b
--- /dev/null
+++ b/js/src/jit-test/lib/census.js
@@ -0,0 +1,161 @@
+// Functions for checking results returned by Debugger.Memory.prototype.takeCensus.
+
+const Census = {};
+
+(function () {
+
+ // Census.walkCensus(subject, name, walker[, ignore])
+ //
+ // Use |walker| to check |subject|, a census object of the sort returned by
+ // Debugger.Memory.prototype.takeCensus: a tree of objects with integers at the
+ // leaves. Use |name| as the name for |subject| in diagnostic messages. Return
+ // the number of leaves of |subject| we visited.
+ //
+ // A walker is an object with three methods:
+ //
+ // - enter(prop): Return the walker we should use to check the property of the
+ // subject census named |prop|. This is for recursing into the subobjects of
+ // the subject.
+ //
+ // - done(ignore): Called after we have called 'enter' on every property of
+ // the subject. Passed the |ignore| set of properties.
+ //
+ // - check(value): Check |value|, a leaf in the subject.
+ //
+ // Walker methods are expected to simply throw if a node we visit doesn't look
+ // right.
+ //
+ // The optional |ignore| parameter allows you to specify a |Set| of property
+ // names which should be ignored. The walker will not traverse such
+ // properties.
+ Census.walkCensus = (subject, name, walker, ignore = new Set()) =>
+ walk(subject, name, walker, ignore, 0);
+
+ function walk(subject, name, walker, ignore, count) {
+ if (typeof subject === 'object') {
+ print(name);
+ for (let prop in subject) {
+ if (ignore.has(prop)) {
+ continue;
+ }
+ count = walk(subject[prop],
+ name + "[" + uneval(prop) + "]",
+ walker.enter(prop),
+ ignore,
+ count);
+ }
+ walker.done(ignore);
+ } else {
+ print(name + " = " + uneval(subject));
+ walker.check(subject);
+ count++;
+ }
+
+ return count;
+ }
+
+ // A walker that doesn't check anything.
+ Census.walkAnything = {
+ enter: () => Census.walkAnything,
+ done: () => undefined,
+ check: () => undefined
+ };
+
+ // A walker that requires all leaves to be zeros.
+ Census.assertAllZeros = {
+ enter: () => Census.assertAllZeros,
+ done: () => undefined,
+ check: elt => assertEq(elt, 0)
+ };
+
+ function expectedObject() {
+ throw "Census mismatch: subject has leaf where basis has nested object";
+ }
+
+ function expectedLeaf() {
+ throw "Census mismatch: subject has nested object where basis has leaf";
+ }
+
+ // Return a function that, given a 'basis' census, returns a census walker that
+ // compares the subject census against the basis. The returned walker calls the
+ // given |compare|, |missing|, and |extra| functions as follows:
+ //
+ // - compare(subjectLeaf, basisLeaf): Check a leaf of the subject against the
+ // corresponding leaf of the basis.
+ //
+ // - missing(prop, value): Called when the subject is missing a property named
+ // |prop| which is present in the basis with value |value|.
+ //
+ // - extra(prop): Called when the subject has a property named |prop|, but the
+ // basis has no such property. This should return a walker that can check
+ // the subject's value.
+ function makeBasisChecker({compare, missing, extra}) {
+ return function makeWalker(basis) {
+ if (typeof basis === 'object') {
+ var unvisited = new Set(Object.getOwnPropertyNames(basis));
+ return {
+ enter: prop => {
+ unvisited.delete(prop);
+ if (prop in basis) {
+ return makeWalker(basis[prop]);
+ } else {
+ return extra(prop);
+ }
+ },
+
+ done: ignore => [...unvisited].filter(p => !ignore.has(p)).forEach(p => missing(p, basis[p])),
+ check: expectedObject
+ };
+ } else {
+ return {
+ enter: expectedLeaf,
+ done: expectedLeaf,
+ check: elt => compare(elt, basis)
+ };
+ }
+ };
+ }
+
+ function missingProp(prop) {
+ throw "Census mismatch: subject lacks property present in basis: " + uneval(prop);
+ }
+
+ function extraProp(prop) {
+ throw "Census mismatch: subject has property not present in basis: " + uneval(prop);
+ }
+
+ // Return a walker that checks that the subject census has counts all equal to
+ // |basis|.
+ Census.assertAllEqual = makeBasisChecker({
+ compare: assertEq,
+ missing: missingProp,
+ extra: extraProp
+ });
+
+ // Return a walker that checks that the subject census has at least as many
+ // items of each category as |basis|.
+ Census.assertAllNotLessThan = makeBasisChecker({
+ compare: (subject, basis) => assertEq(subject >= basis, true),
+ missing: missingProp,
+ extra: () => Census.walkAnything
+ });
+
+ // Return a walker that checks that the subject census has at most as many
+ // items of each category as |basis|.
+ Census.assertAllNotMoreThan = makeBasisChecker({
+ compare: (subject, basis) => assertEq(subject <= basis, true),
+ missing: missingProp,
+ extra: () => Census.walkAnything
+ });
+
+ // Return a walker that checks that the subject census has within |fudge|
+ // items of each category of the count in |basis|.
+ Census.assertAllWithin = function (fudge, basis) {
+ return makeBasisChecker({
+ compare: (subject, basis) => assertEq(Math.abs(subject - basis) <= fudge, true),
+ missing: missingProp,
+ extra: () => Census.walkAnything
+ })(basis);
+ }
+
+})();