tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Census.sys.mjs (5210B)


      1 // Functions for checking results returned by
      2 // Debugger.Memory.prototype.takeCensus and
      3 // HeapSnapshot.prototype.takeCensus. Adapted from js/src/jit-test/lib/census.js.
      4 
      5 export const Census = {};
      6 function dumpn(msg) {
      7  dump("DBG-TEST: Census.sys.mjs: " + msg + "\n");
      8 }
      9 
     10 // Census.walkCensus(subject, name, walker)
     11 //
     12 // Use |walker| to check |subject|, a census object of the sort returned by
     13 // Debugger.Memory.prototype.takeCensus: a tree of objects with integers at the
     14 // leaves. Use |name| as the name for |subject| in diagnostic messages. Return
     15 // the number of leaves of |subject| we visited.
     16 //
     17 // A walker is an object with three methods:
     18 //
     19 // - enter(prop): Return the walker we should use to check the property of the
     20 //   subject census named |prop|. This is for recursing into the subobjects of
     21 //   the subject.
     22 //
     23 // - done(): Called after we have called 'enter' on every property of the
     24 //   subject.
     25 //
     26 // - check(value): Check |value|, a leaf in the subject.
     27 //
     28 // Walker methods are expected to simply throw if a node we visit doesn't look
     29 // right.
     30 Census.walkCensus = (subject, name, walker) => walk(subject, name, walker, 0);
     31 function walk(subject, name, walker, count) {
     32  if (typeof subject === "object") {
     33    dumpn(name);
     34    for (const prop in subject) {
     35      count = walk(
     36        subject[prop],
     37        name + "[" + uneval(prop) + "]",
     38        walker.enter(prop),
     39        count
     40      );
     41    }
     42    walker.done();
     43  } else {
     44    dumpn(name + " = " + uneval(subject));
     45    walker.check(subject);
     46    count++;
     47  }
     48 
     49  return count;
     50 }
     51 
     52 // A walker that doesn't check anything.
     53 Census.walkAnything = {
     54  enter: () => Census.walkAnything,
     55  done: () => undefined,
     56  check: () => undefined,
     57 };
     58 
     59 // A walker that requires all leaves to be zeros.
     60 Census.assertAllZeros = {
     61  enter: () => Census.assertAllZeros,
     62  done: () => undefined,
     63  check: elt => {
     64    if (elt !== 0) {
     65      throw new Error("Census mismatch: expected zero, found " + elt);
     66    }
     67  },
     68 };
     69 
     70 function expectedObject() {
     71  throw new Error(
     72    "Census mismatch: subject has leaf where basis has nested object"
     73  );
     74 }
     75 
     76 function expectedLeaf() {
     77  throw new Error(
     78    "Census mismatch: subject has nested object where basis has leaf"
     79  );
     80 }
     81 
     82 // Return a function that, given a 'basis' census, returns a census walker that
     83 // compares the subject census against the basis. The returned walker calls the
     84 // given |compare|, |missing|, and |extra| functions as follows:
     85 //
     86 // - compare(subjectLeaf, basisLeaf): Check a leaf of the subject against the
     87 //   corresponding leaf of the basis.
     88 //
     89 // - missing(prop, value): Called when the subject is missing a property named
     90 //   |prop| which is present in the basis with value |value|.
     91 //
     92 // - extra(prop): Called when the subject has a property named |prop|, but the
     93 //   basis has no such property. This should return a walker that can check
     94 //   the subject's value.
     95 function makeBasisChecker({ compare, missing, extra }) {
     96  return function makeWalker(basis) {
     97    if (typeof basis === "object") {
     98      const unvisited = new Set(Object.getOwnPropertyNames(basis));
     99      return {
    100        enter: prop => {
    101          unvisited.delete(prop);
    102          if (prop in basis) {
    103            return makeWalker(basis[prop]);
    104          }
    105 
    106          return extra(prop);
    107        },
    108 
    109        done: () => unvisited.forEach(prop => missing(prop, basis[prop])),
    110        check: expectedObject,
    111      };
    112    }
    113 
    114    return {
    115      enter: expectedLeaf,
    116      done: expectedLeaf,
    117      check: elt => compare(elt, basis),
    118    };
    119  };
    120 }
    121 
    122 function missingProp(prop) {
    123  throw new Error(
    124    "Census mismatch: subject lacks property present in basis: " + prop
    125  );
    126 }
    127 
    128 function extraProp(prop) {
    129  throw new Error(
    130    "Census mismatch: subject has property not present in basis: " + prop
    131  );
    132 }
    133 
    134 // Return a walker that checks that the subject census has counts all equal to
    135 // |basis|.
    136 Census.assertAllEqual = makeBasisChecker({
    137  compare: (a, b) => {
    138    if (a !== b) {
    139      throw new Error("Census mismatch: expected " + a + " got " + b);
    140    }
    141  },
    142  missing: missingProp,
    143  extra: extraProp,
    144 });
    145 
    146 function ok(val) {
    147  if (!val) {
    148    throw new Error("Census mismatch: expected truthy, got " + val);
    149  }
    150 }
    151 /* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */
    152 
    153 // Return a walker that checks that the subject census has at least as many
    154 // items of each category as |basis|.
    155 Census.assertAllNotLessThan = makeBasisChecker({
    156  compare: (subject, basis) => ok(subject >= basis),
    157  missing: missingProp,
    158  extra: () => Census.walkAnything,
    159 });
    160 
    161 // Return a walker that checks that the subject census has at most as many
    162 // items of each category as |basis|.
    163 Census.assertAllNotMoreThan = makeBasisChecker({
    164  compare: (subject, basis) => ok(subject <= basis),
    165  missing: missingProp,
    166  extra: () => Census.walkAnything,
    167 });
    168 
    169 // Return a walker that checks that the subject census has within |fudge|
    170 // items of each category of the count in |basis|.
    171 Census.assertAllWithin = function (fudge, basis) {
    172  return makeBasisChecker({
    173    compare: (subject, base) => ok(Math.abs(subject - base) <= fudge),
    174    missing: missingProp,
    175    extra: () => Census.walkAnything,
    176  })(basis);
    177 };