tor-browser

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

assert-offset-columns.js (3013B)


      1 // Set breakpoints "everywhere" in a function, then call the function and check that
      2 // the breakpoints were added are at the expected columns, and the breakpoints
      3 // were executed in th expected order.
      4 //
      5 // `code` is a JS Script. The final line should define a function `f` to validate.
      6 // `expectedBpts` is a string of spaces and carets ('^'). Throws if we don't hit
      7 // breakpoints on exactly the columns indicated by the carets.
      8 // `expectedOrdering` is a string of integer indices for the offsets that are
      9 // executed, in the order that then are executed. Test code can also push
     10 // additional items into this string using items.push("!").
     11 function assertOffsetColumns(code, expectedBpts, expectedOrdering = null) {
     12    if (expectedOrdering === null) {
     13        // The default ordering simply runs the breakpoints in order.
     14        expectedOrdering = Array.from(expectedBpts.match(/\^/g), (_, i) => i).join(" ");
     15    }
     16 
     17    // Define the function `f` in a new global.
     18    const global = newGlobal({newCompartment: true});
     19 
     20    const lines = code.split(/\r?\n|\r]/g);
     21    const initCode = lines.slice(0, -1).join("\n");
     22    const execCode = lines[lines.length - 1];
     23 
     24    // Treat everything but the last line as initialization code.
     25    global.eval(initCode);
     26 
     27    // Run the test code itself.
     28    global.eval(execCode);
     29 
     30    // Allow some tests to append to a log that will show up in expected ordering.
     31    const hits = global.hits = [];
     32    const bpts = new Set();
     33 
     34    // Set breakpoints everywhere and call the function.
     35    const dbg = new Debugger;
     36    let debuggeeFn = dbg.addDebuggee(global).makeDebuggeeValue(global.f);
     37    if (debuggeeFn.isBoundFunction) {
     38        debuggeeFn = debuggeeFn.boundTargetFunction;
     39    }
     40 
     41    const { script } = debuggeeFn;
     42    for (const offset of script.getAllColumnOffsets()) {
     43        assertEq(offset.lineNumber, 1);
     44        assertEq(offset.columnNumber <= execCode.length, true);
     45        bpts.add(offset.columnNumber);
     46 
     47        script.setBreakpoint(offset.offset, {
     48            hit(frame) {
     49                hits.push(offset.columnNumber);
     50            },
     51        });
     52    }
     53    global.f(3);
     54 
     55    const actualBpts = Array.from(execCode, (_, i) => {
     56        return bpts.has(i + 1) ? "^" : " ";
     57    }).join("");
     58 
     59    if (actualBpts.trimEnd() !== expectedBpts.trimEnd()) {
     60        throw new Error(`Assertion failed:
     61                     code: ${execCode}
     62            expected bpts: ${expectedBpts}
     63              actual bpts: ${actualBpts}\n`);
     64    }
     65 
     66    const indexLookup = new Map(
     67        Array.from(bpts).sort().map((col, i) => [col, i]));
     68    const actualOrdering = hits
     69        .map(item => typeof item === "number" ? indexLookup.get(item) : item)
     70        .join(" ");
     71 
     72    if (actualOrdering.trimEnd() !== expectedOrdering.trimEnd()) {
     73        throw new Error(`Assertion failed:
     74                     code: ${execCode}
     75                     bpts: ${expectedBpts}
     76           expected order: ${expectedOrdering}
     77             actual order: ${actualOrdering}\n`);
     78    }
     79 }